912 lines
24 KiB
Vue
912 lines
24 KiB
Vue
<template>
|
||
<view class="route-service-analysis">
|
||
<!-- 报表标题 -->
|
||
<view class="report-header">
|
||
<text class="report-title">按路线的服务区经营状态分析</text>
|
||
<view class="report-period">
|
||
<text class="period-label">分析周期:</text>
|
||
<text class="period-value">{{ analysisPeriod }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 对比分析切换 -->
|
||
<view class="analysis-tabs">
|
||
<view class="tab-item"
|
||
:class="{ active: activeAnalysisType === 'compare' }"
|
||
@click="switchAnalysisType('compare')">
|
||
<text class="tab-text">对比分析</text>
|
||
</view>
|
||
<view class="tab-item"
|
||
:class="{ active: activeAnalysisType === 'yearOverYear' }"
|
||
@click="switchAnalysisType('yearOverYear')">
|
||
<text class="tab-text">同比分析</text>
|
||
</view>
|
||
<view class="tab-item"
|
||
:class="{ active: activeAnalysisType === 'monthOverMonth' }"
|
||
@click="switchAnalysisType('monthOverMonth')">
|
||
<text class="tab-text">环比分析</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 关键指标卡片 -->
|
||
<view class="metrics-row">
|
||
<view class="metric-card">
|
||
<view class="metric-icon revenue"></view>
|
||
<text class="metric-title">总营业额</text>
|
||
<view class="metric-value-container">
|
||
<text class="metric-value">¥{{ formatMoney(totalRevenue) }}</text>
|
||
<text class="metric-unit">万元</text>
|
||
</view>
|
||
<text class="metric-trend" :class="revenueTrend > 0 ? 'positive' : revenueTrend < 0 ? 'negative' : 'neutral'">
|
||
{{ formatTrend(revenueTrend) }}
|
||
</text>
|
||
</view>
|
||
<view class="metric-card">
|
||
<view class="metric-icon traffic"></view>
|
||
<text class="metric-title">总客流量</text>
|
||
<view class="metric-value-container">
|
||
<text class="metric-value">{{ formatNumber(totalTraffic) }}</text>
|
||
<text class="metric-unit">万人次</text>
|
||
</view>
|
||
<text class="metric-trend" :class="trafficTrend > 0 ? 'positive' : trafficTrend < 0 ? 'negative' : 'neutral'">
|
||
{{ formatTrend(trafficTrend) }}
|
||
</text>
|
||
</view>
|
||
<view class="metric-card">
|
||
<view class="metric-icon vehicles"></view>
|
||
<text class="metric-title">总车流量</text>
|
||
<view class="metric-value-container">
|
||
<text class="metric-value">{{ formatNumber(totalVehicles) }}</text>
|
||
<text class="metric-unit">万辆</text>
|
||
</view>
|
||
<text class="metric-trend" :class="vehicleTrend > 0 ? 'positive' : vehicleTrend < 0 ? 'negative' : 'neutral'">
|
||
{{ formatTrend(vehicleTrend) }}
|
||
</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 路线营业额对比图 -->
|
||
<view class="chart-card">
|
||
<view class="chart-header">
|
||
<text class="chart-title">各路线营业额{{ getAnalysisTypeName() }}</text>
|
||
<text class="chart-subtitle">不同路线服务区营业额表现</text>
|
||
</view>
|
||
<view class="chart-content">
|
||
<view class="bar-chart-container">
|
||
<QiunDataCharts
|
||
type="column"
|
||
:opts="revenueChartOpts"
|
||
:chartData="revenueChartData"
|
||
:canvas2d="true"
|
||
:inScrollView="true"
|
||
canvasId="routeRevenueChart"
|
||
/>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 服务区经营状态分布图 -->
|
||
<view class="chart-card">
|
||
<view class="chart-header">
|
||
<text class="chart-title">服务区经营状态分布</text>
|
||
<text class="chart-subtitle">各路线服务区经营状态占比</text>
|
||
</view>
|
||
<view class="chart-content">
|
||
<view class="pie-chart-container">
|
||
<QiunDataCharts
|
||
type="pie"
|
||
:opts="statusChartOpts"
|
||
:chartData="statusChartData"
|
||
:canvas2d="true"
|
||
:inScrollView="true"
|
||
canvasId="serviceAreaStatusChart"
|
||
/>
|
||
<view class="pie-legend">
|
||
<view class="legend-item" v-for="(item, index) in statusData" :key="index">
|
||
<view class="legend-color" :style="{ backgroundColor: item.color }"></view>
|
||
<text class="legend-name">{{ item.name }}</text>
|
||
<text class="legend-value">{{ item.percentage }}%</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 综合指标雷达图 -->
|
||
<view class="chart-card">
|
||
<view class="chart-header">
|
||
<text class="chart-title">服务区综合指标分析</text>
|
||
<text class="chart-subtitle">多维度经营指标雷达图</text>
|
||
</view>
|
||
<view class="chart-content">
|
||
<view class="radar-chart-container">
|
||
<QiunDataCharts
|
||
type="radar"
|
||
:opts="radarChartOpts"
|
||
:chartData="radarChartData"
|
||
:canvas2d="true"
|
||
:inScrollView="true"
|
||
canvasId="radarChart"
|
||
/>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 服务区详细数据卡片 -->
|
||
<view class="chart-card">
|
||
<view class="chart-header">
|
||
<text class="chart-title">服务区详细数据</text>
|
||
<view class="table-actions">
|
||
<text class="action-btn" @click="exportData">导出数据</text>
|
||
</view>
|
||
</view>
|
||
<view class="service-area-cards">
|
||
<view class="area-card" v-for="(item, index) in detailData" :key="index">
|
||
<view class="card-header">
|
||
<text class="area-name">{{ item.serviceAreaName }}</text>
|
||
<text class="route-name">{{ item.routeName }}</text>
|
||
<text class="service-type">{{ item.serviceType }}</text>
|
||
</view>
|
||
<view class="card-content">
|
||
<view class="metrics-row">
|
||
<view class="metric-item">
|
||
<text class="metric-label">营业额</text>
|
||
<text class="metric-value">¥{{ formatMoney(item.revenue) }}</text>
|
||
</view>
|
||
<view class="metric-item">
|
||
<text class="metric-label">增长率</text>
|
||
<text :class="'metric-value ' + (item.growthRate > 10 ? 'growth-high' : item.growthRate > 0 ? 'growth-positive' : item.growthRate < -10 ? 'growth-negative' : 'growth-neutral')">
|
||
{{ formatGrowth(item.growthRate) }}
|
||
</text>
|
||
</view>
|
||
<view class="metric-item">
|
||
<text class="metric-label">运营状态</text>
|
||
<text :class="'status-badge ' + (item.operationalStatus === '正常运营' ? 'status-success' : item.operationalStatus === '升级改造' ? 'status-warning' : item.operationalStatus === '暂停营业' ? 'status-error' : 'status-info')">
|
||
{{ item.operationalStatus }}
|
||
</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import QiunDataCharts from './qiun-data-charts/components/qiun-data-charts/qiun-data-charts.vue'
|
||
|
||
export default {
|
||
components: {
|
||
QiunDataCharts
|
||
},
|
||
|
||
data() {
|
||
return {
|
||
analysisPeriod: '2024年10月',
|
||
activeAnalysisType: 'compare',
|
||
totalRevenue: 45678,
|
||
totalTraffic: 1234,
|
||
totalVehicles: 567,
|
||
revenueTrend: 12.5,
|
||
trafficTrend: 8.3,
|
||
vehicleTrend: 15.7,
|
||
|
||
// 服务区状态分布数据
|
||
statusData: [
|
||
{ name: '正常运营', value: 65, percentage: 65, color: '#52C41A' },
|
||
{ name: '升级改造', value: 15, percentage: 15, color: '#FAAD14' },
|
||
{ name: '暂停营业', value: 12, percentage: 12, color: '#FF7875' },
|
||
{ name: '规划建设', value: 8, percentage: 8, color: '#576EFF' }
|
||
],
|
||
|
||
// 路线数据
|
||
routeData: [
|
||
{
|
||
routeName: 'G56杭瑞高速',
|
||
serviceAreas: ['昆明服务区', '大理服务区', '保山服务区'],
|
||
totalRevenue: 12567,
|
||
revenue: [4567, 3890, 4110],
|
||
traffic: [234, 189, 201],
|
||
vehicles: [123, 98, 105]
|
||
},
|
||
{
|
||
routeName: 'G85渝昆高速',
|
||
serviceAreas: ['昭通服务区', '曲靖服务区'],
|
||
totalRevenue: 9876,
|
||
revenue: [5432, 4444],
|
||
traffic: [178, 156],
|
||
vehicles: [89, 78]
|
||
},
|
||
{
|
||
routeName: 'G80广昆高速',
|
||
serviceAreas: ['文山服务区', '红河服务区', '玉溪服务区'],
|
||
totalRevenue: 8765,
|
||
revenue: [3234, 2789, 2742],
|
||
traffic: [145, 123, 134],
|
||
vehicles: [67, 56, 62]
|
||
},
|
||
{
|
||
routeName: 'G5京昆高速',
|
||
serviceAreas: ['攀枝花服务区', '丽江服务区'],
|
||
totalRevenue: 7654,
|
||
revenue: [4123, 3531],
|
||
traffic: [134, 112],
|
||
vehicles: [61, 51]
|
||
}
|
||
],
|
||
|
||
// 详细数据
|
||
detailData: [
|
||
{
|
||
routeName: 'G56杭瑞高速',
|
||
serviceAreaName: '昆明服务区',
|
||
serviceType: 'A类',
|
||
operationalStatus: '正常运营',
|
||
revenue: 4567,
|
||
growthRate: 15.2
|
||
},
|
||
{
|
||
routeName: 'G56杭瑞高速',
|
||
serviceAreaName: '大理服务区',
|
||
serviceType: 'B类',
|
||
operationalStatus: '正常运营',
|
||
revenue: 3890,
|
||
growthRate: 8.7
|
||
},
|
||
{
|
||
routeName: 'G85渝昆高速',
|
||
serviceAreaName: '昭通服务区',
|
||
serviceType: 'A类',
|
||
operationalStatus: '升级改造',
|
||
revenue: 5432,
|
||
growthRate: -5.3
|
||
},
|
||
{
|
||
routeName: 'G80广昆高速',
|
||
serviceAreaName: '文山服务区',
|
||
serviceType: 'C类',
|
||
operationalStatus: '正常运营',
|
||
revenue: 3234,
|
||
growthRate: 22.1
|
||
}
|
||
]
|
||
}
|
||
},
|
||
|
||
computed: {
|
||
// 营业额图表数据
|
||
revenueChartData() {
|
||
return {
|
||
categories: this.routeData.map(item => item.routeName),
|
||
series: [
|
||
{
|
||
name: this.activeAnalysisType === 'compare' ? '本期' :
|
||
this.activeAnalysisType === 'yearOverYear' ? '今年' : '本月',
|
||
data: this.routeData.map(item => item.totalRevenue)
|
||
},
|
||
...(this.activeAnalysisType !== 'compare' ? [{
|
||
name: this.activeAnalysisType === 'yearOverYear' ? '去年' : '上月',
|
||
data: this.routeData.map(item => Math.round(item.totalRevenue * 0.85))
|
||
}] : [])
|
||
]
|
||
}
|
||
},
|
||
|
||
// 营业额图表配置
|
||
revenueChartOpts() {
|
||
return {
|
||
color: ['#576EFF', '#52C41A', '#FAAD14'],
|
||
padding: [15, 15, 15, 15],
|
||
dataLabel: false,
|
||
legend: {
|
||
show: true,
|
||
position: 'top'
|
||
},
|
||
xAxis: {
|
||
itemCount: 3,
|
||
scrollShow: true,
|
||
scrollAlign: 'right'
|
||
},
|
||
yAxis: {
|
||
gridType: 'dash',
|
||
dashLength: 2,
|
||
data: [{
|
||
min: 0
|
||
}]
|
||
},
|
||
extra: {
|
||
column: {
|
||
type: 'stack',
|
||
width: this.activeAnalysisType === 'compare' ? 40 : 30,
|
||
activeBgColor: '#000000',
|
||
activeBgOpacity: 0.08,
|
||
linearType: 'custom',
|
||
barBorderCircle: true
|
||
}
|
||
}
|
||
}
|
||
},
|
||
|
||
// 状态分布图表数据
|
||
statusChartData() {
|
||
return {
|
||
series: [{
|
||
data: this.statusData.map(item => ({
|
||
name: item.name,
|
||
value: item.value
|
||
}))
|
||
}]
|
||
}
|
||
},
|
||
|
||
// 状态分布图表配置
|
||
statusChartOpts() {
|
||
return {
|
||
color: this.statusData.map(item => item.color),
|
||
padding: [5, 5, 5, 5],
|
||
dataLabel: true,
|
||
legend: {
|
||
show: false
|
||
},
|
||
extra: {
|
||
pie: {
|
||
activeOpacity: 0.5,
|
||
activeRadius: 10,
|
||
offsetAngle: 0,
|
||
labelWidth: 15,
|
||
border: false,
|
||
borderWidth: 3,
|
||
borderColor: '#FFFFFF'
|
||
}
|
||
}
|
||
}
|
||
},
|
||
|
||
// 雷达图数据
|
||
radarChartData() {
|
||
return {
|
||
categories: ['客流量', '车流量', '营业额', '利润率', '增长率', '经营面积'],
|
||
series: [
|
||
{
|
||
name: 'G56杭瑞高速',
|
||
data: [85, 78, 92, 68, 75, 88]
|
||
},
|
||
{
|
||
name: 'G85渝昆高速',
|
||
data: [72, 85, 76, 82, 65, 70]
|
||
},
|
||
{
|
||
name: 'G80广昆高速',
|
||
data: [68, 72, 78, 75, 88, 65]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
|
||
// 雷达图配置
|
||
radarChartOpts() {
|
||
return {
|
||
color: ['#576EFF', '#52C41A', '#FAAD14'],
|
||
padding: [15, 15, 15, 15],
|
||
dataLabel: false,
|
||
legend: {
|
||
show: true,
|
||
position: 'top'
|
||
},
|
||
extra: {
|
||
radar: {
|
||
gridType: 'radar',
|
||
gridColor: '#E0E0E0',
|
||
gridCount: 4,
|
||
opacity: 0.8,
|
||
max: 100,
|
||
border: false
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
|
||
methods: {
|
||
switchAnalysisType(type) {
|
||
this.activeAnalysisType = type;
|
||
},
|
||
|
||
getAnalysisTypeName() {
|
||
const names = {
|
||
compare: '对比',
|
||
yearOverYear: '同比',
|
||
monthOverMonth: '环比'
|
||
};
|
||
return names[this.activeAnalysisType] || '';
|
||
},
|
||
|
||
getTrendClass(trend) {
|
||
return trend > 0 ? 'positive' : trend < 0 ? 'negative' : 'neutral';
|
||
},
|
||
|
||
getStatusClass(status) {
|
||
const classMap = {
|
||
'正常运营': 'success',
|
||
'升级改造': 'warning',
|
||
'暂停营业': 'error',
|
||
'规划建设': 'info'
|
||
};
|
||
return classMap[status] || '';
|
||
},
|
||
|
||
getGrowthClass(growth) {
|
||
return growth > 10 ? 'high' : growth > 0 ? 'positive' : growth < -10 ? 'negative' : 'neutral';
|
||
},
|
||
|
||
formatNumber(num) {
|
||
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
||
},
|
||
|
||
formatMoney(amount) {
|
||
return amount.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
||
},
|
||
|
||
formatTrend(trend) {
|
||
const sign = trend > 0 ? '↑' : trend < 0 ? '↓' : '→';
|
||
return `${sign} ${Math.abs(trend)}%`;
|
||
},
|
||
|
||
formatGrowth(growth) {
|
||
const sign = growth > 0 ? '+' : '';
|
||
return sign + growth + '%'
|
||
},
|
||
|
||
exportData() {
|
||
console.log('导出路线服务区数据');
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped lang="less">
|
||
@primary-color: #667eea;
|
||
@success-color: #52c41a;
|
||
@warning-color: #faad14;
|
||
@error-color: #ff4d4f;
|
||
@info-color: #1890ff;
|
||
@text-primary: #333;
|
||
@text-secondary: #666;
|
||
@text-light: #999;
|
||
@bg-white: #ffffff;
|
||
@border-radius: 16rpx;
|
||
@shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
|
||
|
||
.route-service-analysis {
|
||
.report-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 32rpx;
|
||
padding: 0 8rpx;
|
||
|
||
.report-title {
|
||
font-size: 36rpx;
|
||
font-weight: 600;
|
||
color: @text-primary;
|
||
}
|
||
|
||
.report-period {
|
||
display: flex;
|
||
align-items: center;
|
||
|
||
.period-label {
|
||
font-size: 24rpx;
|
||
color: @text-secondary;
|
||
margin-right: 8rpx;
|
||
}
|
||
|
||
.period-value {
|
||
font-size: 24rpx;
|
||
color: @primary-color;
|
||
font-weight: 500;
|
||
}
|
||
}
|
||
}
|
||
|
||
.analysis-tabs {
|
||
display: flex;
|
||
background: @bg-white;
|
||
border-radius: @border-radius;
|
||
padding: 8rpx;
|
||
margin-bottom: 32rpx;
|
||
box-shadow: @shadow;
|
||
|
||
.tab-item {
|
||
flex: 1;
|
||
text-align: center;
|
||
padding: 16rpx 12rpx;
|
||
border-radius: 12rpx;
|
||
transition: all 0.3s ease;
|
||
|
||
&.active {
|
||
background: @primary-color;
|
||
|
||
.tab-text {
|
||
color: white;
|
||
font-weight: 600;
|
||
}
|
||
}
|
||
|
||
.tab-text {
|
||
font-size: 26rpx;
|
||
color: @text-secondary;
|
||
transition: all 0.3s ease;
|
||
}
|
||
}
|
||
}
|
||
|
||
.metrics-row {
|
||
display: flex;
|
||
gap: 24rpx;
|
||
margin-bottom: 32rpx;
|
||
|
||
.metric-card {
|
||
flex: 1;
|
||
background: @bg-white;
|
||
border-radius: @border-radius;
|
||
padding: 32rpx 24rpx;
|
||
box-shadow: @shadow;
|
||
text-align: center;
|
||
position: relative;
|
||
|
||
.metric-icon {
|
||
width: 48rpx;
|
||
height: 48rpx;
|
||
margin: 0 auto 16rpx;
|
||
border-radius: 50%;
|
||
position: relative;
|
||
|
||
&.revenue {
|
||
background: linear-gradient(135deg, #faad14, #ffc53d);
|
||
&::after { content: '💰'; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 24rpx; }
|
||
}
|
||
|
||
&.traffic {
|
||
background: linear-gradient(135deg, #52c41a, #73d13d);
|
||
&::after { content: '👥'; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 24rpx; }
|
||
}
|
||
|
||
&.vehicles {
|
||
background: linear-gradient(135deg, #1890ff, #40a9ff);
|
||
&::after { content: '🚗'; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 24rpx; }
|
||
}
|
||
}
|
||
|
||
.metric-title {
|
||
font-size: 24rpx;
|
||
color: @text-secondary;
|
||
margin-bottom: 12rpx;
|
||
}
|
||
|
||
.metric-value-container {
|
||
margin-bottom: 8rpx;
|
||
|
||
.metric-value {
|
||
font-size: 32rpx;
|
||
font-weight: 600;
|
||
color: @text-primary;
|
||
display: block;
|
||
}
|
||
|
||
.metric-unit {
|
||
font-size: 20rpx;
|
||
color: @text-light;
|
||
}
|
||
}
|
||
|
||
.metric-trend {
|
||
font-size: 22rpx;
|
||
font-weight: 500;
|
||
|
||
&.positive {
|
||
color: @success-color;
|
||
}
|
||
|
||
&.negative {
|
||
color: @error-color;
|
||
}
|
||
|
||
&.neutral {
|
||
color: @text-secondary;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.chart-card {
|
||
background: @bg-white;
|
||
border-radius: @border-radius;
|
||
padding: 24rpx;
|
||
box-shadow: @shadow;
|
||
margin-bottom: 24rpx;
|
||
|
||
.chart-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: flex-start;
|
||
margin-bottom: 20rpx;
|
||
|
||
.chart-title {
|
||
font-size: 28rpx;
|
||
font-weight: 600;
|
||
color: @text-primary;
|
||
}
|
||
|
||
.chart-subtitle {
|
||
font-size: 22rpx;
|
||
color: @text-light;
|
||
margin-top: 4rpx;
|
||
}
|
||
|
||
.table-actions {
|
||
display: flex;
|
||
gap: 16rpx;
|
||
|
||
.action-btn {
|
||
font-size: 24rpx;
|
||
color: @primary-color;
|
||
padding: 8rpx 16rpx;
|
||
border: 1rpx solid @primary-color;
|
||
border-radius: 8rpx;
|
||
}
|
||
}
|
||
}
|
||
|
||
.chart-content {
|
||
.pie-chart-container {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
|
||
.pie-legend {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
justify-content: center;
|
||
gap: 16rpx;
|
||
margin-top: 16rpx;
|
||
|
||
.legend-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8rpx;
|
||
|
||
.legend-color {
|
||
width: 12rpx;
|
||
height: 12rpx;
|
||
border-radius: 2rpx;
|
||
}
|
||
|
||
.legend-name {
|
||
font-size: 22rpx;
|
||
color: @text-secondary;
|
||
}
|
||
|
||
.legend-value {
|
||
font-size: 22rpx;
|
||
color: @text-primary;
|
||
font-weight: 600;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.bar-chart-container,
|
||
.radar-chart-container {
|
||
width: 100%;
|
||
}
|
||
}
|
||
|
||
.data-table {
|
||
.table-header {
|
||
display: flex;
|
||
background: #f5f7fa;
|
||
border-radius: 8rpx 8rpx 0 0;
|
||
font-weight: 600;
|
||
|
||
.header-cell {
|
||
flex: 1;
|
||
padding: 16rpx 12rpx;
|
||
font-size: 24rpx;
|
||
color: @text-primary;
|
||
text-align: center;
|
||
border-right: 1rpx solid #e0e0e0;
|
||
|
||
&:last-child {
|
||
border-right: none;
|
||
}
|
||
}
|
||
}
|
||
|
||
.table-body {
|
||
.table-row {
|
||
display: flex;
|
||
border-bottom: 1rpx solid #f0f0f0;
|
||
|
||
&:last-child {
|
||
border-bottom: none;
|
||
}
|
||
|
||
.body-cell {
|
||
flex: 1;
|
||
padding: 16rpx 12rpx;
|
||
font-size: 24rpx;
|
||
color: @text-secondary;
|
||
text-align: center;
|
||
border-right: 1rpx solid #f0f0f0;
|
||
|
||
&:last-child {
|
||
border-right: none;
|
||
}
|
||
|
||
.status-tag {
|
||
padding: 4rpx 12rpx;
|
||
border-radius: 12rpx;
|
||
font-size: 20rpx;
|
||
color: white;
|
||
font-weight: 500;
|
||
|
||
&.success {
|
||
background: @success-color;
|
||
}
|
||
|
||
&.warning {
|
||
background: @warning-color;
|
||
}
|
||
|
||
&.error {
|
||
background: @error-color;
|
||
}
|
||
|
||
&.info {
|
||
background: @info-color;
|
||
}
|
||
}
|
||
|
||
.growth-rate {
|
||
font-weight: 600;
|
||
|
||
&.high {
|
||
color: @success-color;
|
||
}
|
||
|
||
&.positive {
|
||
color: @success-color;
|
||
}
|
||
|
||
&.negative {
|
||
color: @error-color;
|
||
}
|
||
|
||
&.neutral {
|
||
color: @text-secondary;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.service-area-cards {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 16rpx;
|
||
|
||
.area-card {
|
||
background: #f8f9fa;
|
||
border-radius: 12rpx;
|
||
padding: 20rpx;
|
||
border: 1rpx solid #e9ecef;
|
||
|
||
.card-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 16rpx;
|
||
padding-bottom: 12rpx;
|
||
border-bottom: 1rpx solid #e9ecef;
|
||
|
||
.area-name {
|
||
font-size: 28rpx;
|
||
font-weight: 600;
|
||
color: @text-primary;
|
||
flex: 1;
|
||
}
|
||
|
||
.route-name {
|
||
font-size: 22rpx;
|
||
color: @text-secondary;
|
||
background: #e3f2fd;
|
||
padding: 4rpx 12rpx;
|
||
border-radius: 8rpx;
|
||
margin: 0 8rpx;
|
||
}
|
||
|
||
.service-type {
|
||
font-size: 22rpx;
|
||
color: @primary-color;
|
||
background: #f0f5ff;
|
||
padding: 4rpx 12rpx;
|
||
border-radius: 8rpx;
|
||
font-weight: 500;
|
||
}
|
||
}
|
||
|
||
.card-content {
|
||
.metrics-row {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
gap: 16rpx;
|
||
|
||
.metric-item {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
text-align: center;
|
||
|
||
.metric-label {
|
||
font-size: 22rpx;
|
||
color: @text-secondary;
|
||
margin-bottom: 8rpx;
|
||
}
|
||
|
||
.metric-value {
|
||
font-size: 26rpx;
|
||
font-weight: 600;
|
||
color: @text-primary;
|
||
|
||
&.growth-high {
|
||
color: #52c41a;
|
||
}
|
||
|
||
&.growth-positive {
|
||
color: #52c41a;
|
||
}
|
||
|
||
&.growth-negative {
|
||
color: #ff4d4f;
|
||
}
|
||
|
||
&.growth-neutral {
|
||
color: @text-secondary;
|
||
}
|
||
}
|
||
|
||
.status-badge {
|
||
padding: 6rpx 16rpx;
|
||
border-radius: 16rpx;
|
||
font-size: 22rpx;
|
||
color: white;
|
||
font-weight: 500;
|
||
|
||
&.status-success {
|
||
background: @success-color;
|
||
}
|
||
|
||
&.status-warning {
|
||
background: @warning-color;
|
||
}
|
||
|
||
&.status-error {
|
||
background: @error-color;
|
||
}
|
||
|
||
&.status-info {
|
||
background: @info-color;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</style> |