ccy_DIB/pages/DigitalIntelligenceDashboard/components/RegionalServiceAreaAnalysis.vue
ylj20011123 0eb131cda5 update
2025-10-24 16:25:52 +08:00

1314 lines
35 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="regional-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 regions"></view>
<text class="metric-title">覆盖区域</text>
<view class="metric-value-container">
<text class="metric-value">{{ regionCount }}</text>
<text class="metric-unit"></text>
</view>
</view>
<view class="metric-card">
<view class="metric-icon service-areas"></view>
<text class="metric-title">服务区总数</text>
<view class="metric-value-container">
<text class="metric-value">{{ serviceAreaCount }}</text>
<text class="metric-unit"></text>
</view>
</view>
<view class="metric-card">
<view class="metric-icon avg-revenue"></view>
<text class="metric-title">平均营业额</text>
<view class="metric-value-container">
<text class="metric-value">¥{{ formatMoney(avgRevenue) }}</text>
<text class="metric-unit">万元</text>
</view>
</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="regionRevenueChartOpts" :chartData="regionRevenueChartData"
:canvas2d="true" :inScrollView="true" canvasId="regionRevenueChart" />
</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="distributionChartOpts" :chartData="distributionChartData" :canvas2d="true"
:inScrollView="true" canvasId="distributionChart" tooltipFormat="distributionChartData" />
</view>
<!-- 自定义可滚动图例 -->
<view class="custom-region-legend">
<scroll-view class="legend-scroll" scroll-x="true" show-scrollbar="false">
<view class="legend-items">
<view v-for="(item, index) in regionLegendData" :key="index" class="legend-item"
@tap="onLegendTap(index)">
<view class="legend-color" :style="{ backgroundColor: item.color }"></view>
<text class="legend-name">{{ item.name }}</text>
<!-- 只显示名称,不显示百分比 -->
</view>
</view>
</scroll-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="region-metrics-cards">
<view class="region-card" v-for="(region, index) in heatmapData" :key="index">
<view class="region-header">
<text class="region-name">{{ region.name }}区域</text>
<view class="overall-score">
<text class="score-label">综合评分</text>
<text class="score-value">{{ Math.round((region.traffic + region.vehicles + region.revenue +
region.profit + region.growth) / 5) }}</text>
</view>
</view>
<view class="metrics-grid">
<view class="metric-box">
<text class="metric-label">客流量</text>
<text
:class="['metric-score', region.traffic >= 85 ? 'high' : region.traffic >= 70 ? 'medium-high' : region.traffic >= 55 ? 'medium' : region.traffic >= 40 ? 'medium-low' : 'low']">{{
region.traffic }}</text>
</view>
<view class="metric-box">
<text class="metric-label">车流量</text>
<text
:class="['metric-score', region.vehicles >= 85 ? 'high' : region.vehicles >= 70 ? 'medium-high' : region.vehicles >= 55 ? 'medium' : region.vehicles >= 40 ? 'medium-low' : 'low']">{{
region.vehicles }}</text>
</view>
<view class="metric-box">
<text class="metric-label">营业额</text>
<text
:class="['metric-score', region.revenue >= 85 ? 'high' : region.revenue >= 70 ? 'medium-high' : region.revenue >= 55 ? 'medium' : region.revenue >= 40 ? 'medium-low' : 'low']">{{
region.revenue }}</text>
</view>
<view class="metric-box">
<text class="metric-label">利润率</text>
<text
:class="['metric-score', region.profit >= 85 ? 'high' : region.profit >= 70 ? 'medium-high' : region.profit >= 55 ? 'medium' : region.profit >= 40 ? 'medium-low' : 'low']">{{
region.profit }}</text>
</view>
<view class="metric-box">
<text class="metric-label">增长率</text>
<text
:class="['metric-score', region.growth >= 85 ? 'high' : region.growth >= 70 ? 'medium-high' : region.growth >= 55 ? 'medium' : region.growth >= 40 ? 'medium-low' : 'low']">{{
region.growth }}</text>
</view>
</view>
</view>
</view>
<view class="heatmap-legend">
<view class="legend-items">
<view class="legend-item">
<view class="legend-color low"></view>
<text class="legend-text">低 (0-39)</text>
</view>
<view class="legend-item">
<view class="legend-color medium-low"></view>
<text class="legend-text">中低 (40-54)</text>
</view>
<view class="legend-item">
<view class="legend-color medium"></view>
<text class="legend-text">中 (55-69)</text>
</view>
<view class="legend-item">
<view class="legend-color medium-high"></view>
<text class="legend-text">中高 (70-84)</text>
</view>
<view class="legend-item">
<view class="legend-color high"></view>
<text class="legend-text">高 (85-100)</text>
</view>
</view>
</view>
</view>
</view>
<!-- 区域类型分析图 -->
<view class="chart-card">
<view class="chart-header">
<text class="chart-title">各区域服务区类型分析</text>
<text class="chart-subtitle">A类、B类、C类服务区分布对比</text>
</view>
<view class="chart-content">
<view class="stacked-bar-container">
<QiunDataCharts type="column" :opts="typeAnalysisChartOpts" :chartData="typeAnalysisChartData"
:canvas2d="true" :inScrollView="true" canvasId="typeAnalysisChart" />
</view>
<view class="type-legend">
<view class="legend-item">
<view class="legend-color type-a"></view>
<text class="legend-text">A类服务区</text>
</view>
<view class="legend-item">
<view class="legend-color type-b"></view>
<text class="legend-text">B类服务区</text>
</view>
<view class="legend-item">
<view class="legend-color type-c"></view>
<text class="legend-text">C类服务区</text>
</view>
</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">
<view class="area-info">
<text class="area-name">{{ item.serviceAreaName }}</text>
<text class="region-name">{{ item.regionName }}</text>
</view>
<view class="area-badges">
<text class="type-badge" :class="item.serviceType === 'A类' ? 'type-a' :
item.serviceType === 'B类' ? 'type-b' :
item.serviceType === 'C类' ? 'type-c' : ''">
{{ item.serviceType }}
</text>
<text class="status-badge" :class="item.operationalStatus === '正常运营' ? 'success' :
item.operationalStatus === '升级改造' ? 'warning' :
item.operationalStatus === '暂停营业' ? 'error' : 'info'">
{{ item.operationalStatus }}
</text>
</view>
</view>
<view class="card-content">
<view class="metrics-row">
<view class="metric-item">
<text class="metric-label">经营面积</text>
<text class="metric-value">{{ item.businessArea }}</text>
</view>
<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 profit-rate" :class="item.profitRate >= 15 ? 'high' :
item.profitRate >= 10 ? 'positive' :
item.profitRate >= 5 ? 'neutral' : 'negative'">
{{ formatProfit(item.profitRate) }}
</text>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import QiunDataCharts from './qiun-data-charts/components/qiun-data-charts/qiun-data-charts.vue'
import request from "@/util/index.js";
export default {
components: {
QiunDataCharts
},
data() {
return {
analysisPeriod: '2024年10月',
activeAnalysisType: 'compare',
regionCount: 16,
serviceAreaCount: 42,
avgRevenue: 3425,
// 区域分布数据
distributionData: [],
// 区域营业额数据
regionData: [
{
name: '昆明',
totalRevenue: 15678,
currentPeriod: [4567, 3890, 3214, 4007],
lastPeriod: [3890, 3456, 2987, 3543],
serviceAreas: 8
},
{
name: '曲靖',
totalRevenue: 9876,
currentPeriod: [2345, 1987, 2134, 3410],
lastPeriod: [1987, 1765, 1876, 2987],
serviceAreas: 6
},
{
name: '大理',
totalRevenue: 8765,
currentPeriod: [2123, 2345, 1876, 2421],
lastPeriod: [1876, 1987, 1654, 2098],
serviceAreas: 7
},
{
name: '红河',
totalRevenue: 7654,
currentPeriod: [1765, 1598, 2134, 2157],
lastPeriod: [1598, 1432, 1876, 1987],
serviceAreas: 5
},
{
name: '昭通',
totalRevenue: 6543,
currentPeriod: [1432, 1321, 1876, 1914],
lastPeriod: [1321, 1234, 1654, 1765],
serviceAreas: 4
}
],
// 热力图数据
heatmapData: [
{
name: '昆明',
traffic: 95,
vehicles: 88,
revenue: 92,
profit: 78,
growth: 85
},
{
name: '曲靖',
traffic: 75,
vehicles: 82,
revenue: 78,
profit: 72,
growth: 68
},
{
name: '大理',
traffic: 82,
vehicles: 76,
revenue: 74,
profit: 85,
growth: 79
},
{
name: '红河',
traffic: 68,
vehicles: 72,
revenue: 70,
profit: 68,
growth: 72
},
{
name: '昭通',
traffic: 62,
vehicles: 68,
revenue: 65,
profit: 70,
growth: 75
}
],
// 服务区类型数据
typeData: [
{
region: '昆明',
typeA: 3,
typeB: 3,
typeC: 2
},
{
region: '曲靖',
typeA: 2,
typeB: 2,
typeC: 2
},
{
region: '大理',
typeA: 2,
typeB: 3,
typeC: 2
},
{
region: '红河',
typeA: 1,
typeB: 2,
typeC: 2
},
{
region: '昭通',
typeA: 1,
typeB: 2,
typeC: 1
}
],
// 详细数据
detailData: [
{
regionName: '昆明市',
serviceAreaName: '昆明服务区',
serviceType: 'A类',
operationalStatus: '正常运营',
businessArea: 8500,
revenue: 4567,
profitRate: 18.5
},
{
regionName: '昆明市',
serviceAreaName: '安宁服务区',
serviceType: 'B类',
operationalStatus: '正常运营',
businessArea: 6200,
revenue: 3890,
profitRate: 15.2
},
{
regionName: '曲靖市',
serviceAreaName: '曲靖服务区',
serviceType: 'A类',
operationalStatus: '升级改造',
businessArea: 7800,
revenue: 2345,
profitRate: -2.3
},
{
regionName: '大理州',
serviceAreaName: '大理服务区',
serviceType: 'B类',
operationalStatus: '正常运营',
businessArea: 5500,
revenue: 2123,
profitRate: 16.8
},
{
regionName: '红河州',
serviceAreaName: '开远服务区',
serviceType: 'C类',
operationalStatus: '正常运营',
businessArea: 4200,
revenue: 1765,
profitRate: 12.3
}
]
}
},
computed: {
// 区域营业额图表数据
regionRevenueChartData() {
return {
categories: this.regionData.map(item => item.name),
series: [
{
name: this.activeAnalysisType === 'compare' ? '本期' :
this.activeAnalysisType === 'yearOverYear' ? '今年' : '本月',
data: this.regionData.map(item => item.totalRevenue)
},
...(this.activeAnalysisType !== 'compare' ? [{
name: this.activeAnalysisType === 'yearOverYear' ? '去年' : '上月',
data: this.regionData.map(item => Math.round(item.totalRevenue * 0.88))
}] : [])
]
}
},
// 区域营业额图表配置
regionRevenueChartOpts() {
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: 'group',
width: this.activeAnalysisType === 'compare' ? 35 : 25,
activeBgColor: '#000000',
activeBgOpacity: 0.08,
linearType: 'custom',
barBorderCircle: true
}
}
}
},
// 区域分布饼图数据
distributionChartData() {
// 按服务区数量从大到小排序
const sortedData = [...this.distributionData].sort((a, b) => b.value - a.value);
return {
series: [{
data: sortedData.map(item => ({
name: item.name,
value: item.value
}))
}]
}
},
// 区域分布饼图配置
distributionChartOpts() {
return {
color: ['#576EFF', '#52C41A', '#FAAD14', '#FF4D4F', '#13C2C2', '#722ED1', '#FA541C', '#EB2F96'],
padding: [5, 5, 5, 5],
dataLabel: false, // 关闭数据标签,避免拥挤
legend: {
show: false // 关闭原生图例
},
extra: {
pie: {
activeOpacity: 0.5,
activeRadius: 10,
offsetAngle: 0,
labelWidth: 15,
border: false,
borderWidth: 3,
borderColor: '#FFFFFF'
}
}
}
},
// 类型分析图表数据
typeAnalysisChartData() {
return {
categories: this.typeData.map(item => item.region),
series: [
{
name: 'A类服务区',
data: this.typeData.map(item => item.typeA)
},
{
name: 'B类服务区',
data: this.typeData.map(item => item.typeB)
},
{
name: 'C类服务区',
data: this.typeData.map(item => item.typeC)
}
]
}
},
// 类型分析图表配置
typeAnalysisChartOpts() {
return {
color: ['#576EFF', '#52C41A', '#FAAD14'],
padding: [15, 15, 15, 15],
dataLabel: false,
legend: {
show: false
},
xAxis: {
itemCount: 3,
scrollShow: true,
scrollAlign: 'right'
},
yAxis: {
gridType: 'dash',
dashLength: 2,
data: [{
min: 0
}]
},
extra: {
column: {
type: 'stack',
width: 40,
activeBgColor: '#000000',
activeBgOpacity: 0.08,
linearType: 'custom',
barBorderCircle: true
}
}
}
},
// 区域分布图例数据
regionLegendData() {
const colors = ['#576EFF', '#52C41A', '#FAAD14', '#FF4D4F', '#13C2C2', '#722ED1', '#FA541C', '#EB2F96'];
// 按服务区数量从大到小排序,确保与饼图顺序一致
const sortedData = [...this.distributionData].sort((a, b) => b.value - a.value);
return sortedData.map((item, index) => ({
name: item.name,
value: item.value,
color: colors[index % colors.length]
}));
}
},
onReady() {
// 获取整个组件的数据
this.handleGetAllData()
},
methods: {
// 获取整个组件的数据
handleGetAllData() {
// 获取服务区区域分布数据
this.handleGetServiceAreaData()
},
// 获取服务区区域分布数据
async handleGetServiceAreaData() {
const req = {
ProvinceCode: "530000",
StatisticsType: 1000,
ShowWholePower: true
}
const data = await request.$apiGet(
"EShangApiMain/BaseInfo/GetServerpartTree",
req
);
let list = data.Result_Data.List
console.log('服务区区域分布数据', list);
let res = []
if (list && list.length > 0) {
list.forEach((item) => {
if (item.children && item.children.length > 0) {
res.push({ name: item.label, value: item.children && item.children.length > 0 ? item.children.length : 0 })
}
})
}
console.log('dadasd', res);
this.distributionData = res
},
switchAnalysisType(type) {
this.activeAnalysisType = type;
},
getAnalysisTypeName() {
const names = {
compare: '对比',
yearOverYear: '同比',
monthOverMonth: '环比'
};
return names[this.activeAnalysisType] || '';
},
getHeatmapClass(value) {
if (value >= 85) return 'high';
if (value >= 70) return 'medium-high';
if (value >= 55) return 'medium';
if (value >= 40) return 'medium-low';
return 'low';
},
getTypeClass(type) {
const classMap = {
'A类': 'type-a',
'B类': 'type-b',
'C类': 'type-c'
};
return classMap[type] || '';
},
getStatusClass(status) {
const classMap = {
'正常运营': 'success',
'升级改造': 'warning',
'暂停营业': 'error',
'规划建设': 'info'
};
return classMap[status] || '';
},
getProfitClass(profit) {
if (profit >= 15) return 'high';
if (profit >= 10) return 'positive';
if (profit >= 5) return 'neutral';
return 'negative';
},
formatNumber(num) {
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
},
formatMoney(amount) {
return amount.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
},
formatProfit(profit) {
return profit + '%'
},
exportData() {
console.log('导出区域服务区数据');
},
// 图例点击事件
onLegendTap(index) {
console.log('点击图例', index);
}
}
}
</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);
.regional-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;
&.regions {
background: linear-gradient(135deg, #576EFF, #7C8FFF);
&::after {
content: '🗺️';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 24rpx;
}
}
&.service-areas {
background: linear-gradient(135deg, #52C41A, #73D13D);
&::after {
content: '🏪';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 24rpx;
}
}
&.avg-revenue {
background: linear-gradient(135deg, #FAAD14, #FFC53D);
&::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;
}
}
}
}
.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,
.stacked-bar-container {
width: 100%;
}
.custom-region-legend {
width: 100%;
margin-top: 16rpx;
.legend-scroll {
width: 100%;
white-space: nowrap;
.legend-items {
display: inline-flex;
padding: 0 8rpx;
gap: 24rpx;
.legend-item {
display: flex;
align-items: center;
gap: 8rpx;
padding: 8rpx 12rpx;
background: #f8f9fa;
border-radius: 16rpx;
white-space: nowrap;
transition: all 0.3s ease;
&:active {
background: #e6f7ff;
transform: scale(0.95);
}
.legend-color {
width: 16rpx;
height: 16rpx;
border-radius: 50%;
flex-shrink: 0;
}
.legend-name {
font-size: 24rpx;
color: @text-secondary;
font-weight: 500;
}
}
}
}
}
.type-legend {
display: flex;
justify-content: center;
gap: 32rpx;
margin-top: 16rpx;
.legend-item {
display: flex;
align-items: center;
gap: 8rpx;
.legend-color {
width: 12rpx;
height: 12rpx;
border-radius: 2rpx;
&.type-a {
background: #576EFF;
}
&.type-b {
background: #52C41A;
}
&.type-c {
background: #FAAD14;
}
}
.legend-text {
font-size: 22rpx;
color: @text-secondary;
}
}
}
.region-metrics-cards {
display: flex;
flex-direction: column;
gap: 20rpx;
.region-card {
background: #f8f9fa;
border-radius: 12rpx;
padding: 20rpx;
border: 1rpx solid #e9ecef;
.region-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16rpx;
padding-bottom: 12rpx;
border-bottom: 1rpx solid #e9ecef;
.region-name {
font-size: 28rpx;
font-weight: 600;
color: @text-primary;
}
.overall-score {
display: flex;
flex-direction: column;
align-items: center;
background: @primary-color;
color: white;
padding: 8rpx 16rpx;
border-radius: 8rpx;
.score-label {
font-size: 18rpx;
opacity: 0.8;
}
.score-value {
font-size: 24rpx;
font-weight: 600;
}
}
}
.metrics-grid {
display: flex;
flex-wrap: wrap;
gap: 12rpx;
.metric-box {
flex: 1;
min-width: calc(33.333% - 8rpx);
display: flex;
flex-direction: column;
align-items: center;
padding: 12rpx 8rpx;
background: white;
border-radius: 8rpx;
border: 1rpx solid #f0f0f0;
.metric-label {
font-size: 20rpx;
color: @text-secondary;
margin-bottom: 8rpx;
}
.metric-score {
font-size: 26rpx;
font-weight: 600;
&.high {
color: #e74c3c;
}
&.medium-high {
color: #e67e22;
}
&.medium {
color: #f1c40f;
}
&.medium-low {
color: #2ecc71;
}
&.low {
color: #3498db;
}
}
}
}
}
}
.heatmap-legend {
margin-top: 24rpx;
.legend-items {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 16rpx;
.legend-item {
display: flex;
align-items: center;
gap: 8rpx;
.legend-color {
width: 16rpx;
height: 16rpx;
border-radius: 4rpx;
&.low {
background: #3498db;
}
&.medium-low {
background: #2ecc71;
}
&.medium {
background: #f1c40f;
}
&.medium-high {
background: #e67e22;
}
&.high {
background: #e74c3c;
}
}
.legend-text {
font-size: 20rpx;
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: flex-start;
margin-bottom: 16rpx;
.area-info {
flex: 1;
.area-name {
display: block;
font-size: 32rpx;
font-weight: 600;
color: @text-primary;
margin-bottom: 8rpx;
}
.region-name {
display: block;
font-size: 24rpx;
color: @text-secondary;
}
}
.area-badges {
display: flex;
flex-direction: column;
gap: 8rpx;
align-items: flex-end;
.type-badge {
padding: 6rpx 12rpx;
border-radius: 8rpx;
font-size: 20rpx;
color: white;
font-weight: 500;
&.type-a {
background: #576EFF;
}
&.type-b {
background: #52C41A;
}
&.type-c {
background: #FAAD14;
}
}
.status-badge {
padding: 6rpx 12rpx;
border-radius: 8rpx;
font-size: 20rpx;
color: white;
font-weight: 500;
&.success {
background: @success-color;
}
&.warning {
background: @warning-color;
}
&.error {
background: @error-color;
}
&.info {
background: @info-color;
}
}
}
}
.card-content {
.metrics-row {
display: flex;
gap: 16rpx;
.metric-item {
flex: 1;
background: white;
padding: 16rpx;
border-radius: 8rpx;
border: 1rpx solid #f0f0f0;
text-align: center;
.metric-label {
display: block;
font-size: 22rpx;
color: @text-secondary;
margin-bottom: 8rpx;
}
.metric-value {
display: block;
font-size: 28rpx;
font-weight: 600;
color: @text-primary;
&.profit-rate {
&.high {
color: @success-color;
}
&.positive {
color: @success-color;
}
&.neutral {
color: @warning-color;
}
&.negative {
color: @error-color;
}
}
}
}
}
}
}
}
}
}
</style>