refactor(wel): 重构欢迎页为模块化组件

- 将欢迎页整体结构拆分为多个功能区组件,提高代码可维护性
- 移除原有欢迎横幅、指标卡、图表区、下方区及快捷入口的静态实现
- 引入并注册 SectionKpi、SectionStructure、SectionBusiness 等八个子组件
- 删除冗余样式,更新整体背景和布局样式
- 精简模板内容,仅保留子组件渲染及页脚版权信息
- 移除无用的响应式数据、计算属性及方法
- 包含依赖包 echarts 的新增,支持后续图表功能开发
This commit is contained in:
2026-09-30 17:39:42 +08:00
parent 50c1afe9c8
commit 0b81001ce7
18 changed files with 1479 additions and 824 deletions
+46
View File
@@ -0,0 +1,46 @@
<template>
<div class="wel-card rank-panel">
<div class="panel-title">
{{ title }}
<span v-if="unit" class="panel-title__unit">{{ unit }}</span>
</div>
<wel-chart
v-if="type === 'rank'"
:option="rankOpt"
:height="height"
/>
<wel-chart v-else :option="diffOpt" :height="height" />
</div>
</template>
<script>
import WelChart from './wel-chart.vue';
import { rankOption, diffOption } from '../chart-options';
export default {
name: 'rank-panel',
components: { WelChart },
props: {
title: { type: String, required: true },
unit: { type: String, default: '' },
/* rank = 普通排行;diff = 盈亏双向对比 */
type: { type: String, default: 'rank' },
color: { type: String, default: '#4a90e2' },
items: { type: Array, required: true },
height: { type: String, default: '300px' },
nameWidth: { type: Number, default: 100 },
},
computed: {
rankOpt() {
return rankOption(this.items, { color: this.color, unit: this.unit, nameWidth: this.nameWidth });
},
diffOpt() {
return diffOption(this.items);
},
},
};
</script>
<style lang="scss" scoped>
@import '../dashboard.scss';
</style>
@@ -0,0 +1,164 @@
<template>
<section class="wel-sec">
<div class="wel-sec__head">
<span class="wel-sec__title">业务单元情况</span>
<wel-filters condition-label="业务单元" />
</div>
<el-row :gutter="16">
<el-col v-for="p in panels" :key="p.title" :xs="24" :md="12">
<rank-panel
:title="p.title"
:unit="p.unit"
:type="p.type"
:color="p.color"
:items="p.items"
:height="p.height"
:name-width="p.nameWidth"
class="business-panel"
/>
</el-col>
</el-row>
</section>
</template>
<script>
import RankPanel from './rank-panel.vue';
import WelFilters from './wel-filters.vue';
export default {
name: 'section-business',
components: { RankPanel, WelFilters },
data() {
return {
// Mock:业务单元排行数据,对接统计接口后替换
panels: [
{
title: '营业收入排行',
unit: '万元',
type: 'rank',
color: '#4a90e2',
height: '320px',
items: [
{ name: '广西物产集团', value: 5218.7, change: 12.3 },
{ name: '南宁港务物流', value: 4183.4, change: 8.6 },
{ name: '柳州钢铁物流', value: 3603.9, change: -2.4 },
{ name: '北部湾港务', value: 3131.7, change: 5.1 },
{ name: '桂林粮油储运', value: 2750.3, change: 9.8 },
{ name: '玉林建材集团', value: 2455.5, change: -1.2 },
{ name: '钦州石化物流', value: 2088.3, change: 6.5 },
{ name: '贵港航运公司', value: 1823.5, change: 3.9 },
{ name: '百色矿产运输', value: 1588.4, change: -4.7 },
{ name: '梧州商贸物流', value: 1214.8, change: 2.2 },
],
},
{
title: '运输情况排行',
unit: '单',
type: 'rank',
color: '#2bb3a3',
height: '320px',
items: [
{ name: '广西物产集团', value: 238.2, change: 9.4 },
{ name: '南宁港务物流', value: 196.3, change: 6.7 },
{ name: '柳州钢铁物流', value: 168.1, change: 3.2 },
{ name: '北部湾港务', value: 154.7, change: -2.8 },
{ name: '桂林粮油储运', value: 139.2, change: 7.5 },
{ name: '玉林建材集团', value: 128.6, change: 4.1 },
{ name: '钦州石化物流', value: 118.3, change: -1.6 },
{ name: '贵港航运公司', value: 106.2, change: 5.3 },
{ name: '百色矿产运输', value: 98.8, change: 2.9 },
{ name: '梧州商贸物流', value: 89.6, change: -3.4 },
],
},
{
title: '各部门毛利占比',
unit: '%',
type: 'rank',
color: '#c9a227',
height: '320px',
items: [
{ name: '公路运输一部', value: 30.7 },
{ name: '公路运输二部', value: 28.2 },
{ name: '铁路物流部', value: 23.2 },
{ name: '水运事业部', value: 19.6 },
{ name: '多式联运部', value: 15.2 },
{ name: '仓储配送部', value: 13.1 },
{ name: '冷链事业部', value: 10.4 },
{ name: '大件运输部', value: 8.6 },
{ name: '危险品运输部', value: 5.2 },
{ name: '综合业务部', value: 2.8 },
],
},
{
title: '项目盈亏对比',
unit: '万元',
type: 'diff',
color: '#e04b4b',
height: '320px',
items: [
{ name: '铝锭外运项目', value: 156.5 },
{ name: '冷链城配项目', value: 134.8 },
{ name: '钢材南下项目', value: 118.2 },
{ name: '粮食储备调运', value: 96.1 },
{ name: '矿石短驳项目', value: 82.6 },
{ name: '集装箱班列', value: 74.3 },
{ name: '化工原料运输', value: 61.2 },
{ name: '建材集散运输', value: 48.9 },
{ name: '汽车零部件配送', value: 21.5 },
{ name: '设备大件运输', value: 16.2 },
{ name: '生鲜冷链专线', value: -8.3 },
{ name: '危化品试点线', value: -25.4 },
],
},
{
title: '运单量排行',
unit: '单',
type: 'rank',
color: '#4a90e2',
height: '320px',
items: [
{ name: '南宁分部', value: 320, change: 6.3 },
{ name: '柳州分部', value: 273, change: 4.8 },
{ name: '桂林分部', value: 241, change: -2.1 },
{ name: '玉林分部', value: 215, change: 8.2 },
{ name: '钦州港分部', value: 203, change: 3.6 },
{ name: '贵港分部', value: 187, change: -1.4 },
{ name: '百色分部', value: 158, change: 5.7 },
{ name: '梧州分部', value: 132, change: 2.3 },
{ name: '北海分部', value: 108, change: -3.9 },
{ name: '河池分部', value: 86, change: 1.6 },
],
},
{
title: '运输收入排行',
unit: '万元',
type: 'rank',
color: '#8b5cf6',
height: '320px',
items: [
{ name: '公路整车', value: 1863.2, change: 7.1 },
{ name: '铁路整车', value: 1421.8, change: 4.5 },
{ name: '水运集装箱', value: 1182.3, change: 9.2 },
{ name: '公路零担', value: 968.5, change: 2.8 },
{ name: '多式联运', value: 812.4, change: 11.6 },
{ name: '航空货运', value: 655.7, change: -1.8 },
{ name: '冷链专线', value: 542.1, change: 6.4 },
{ name: '大件运输', value: 388.9, change: 3.1 },
{ name: '危险品运输', value: 296.3, change: -2.5 },
{ name: '仓储增值服务', value: 184.6, change: 8.8 },
],
},
],
};
},
};
</script>
<style lang="scss" scoped>
@import '../dashboard.scss';
.business-panel {
margin-bottom: 16px;
}
</style>
@@ -0,0 +1,68 @@
<template>
<section class="wel-sec">
<div class="wel-sec__head">
<span class="wel-sec__title">财务情况</span>
<wel-filters condition-label="核算口径" />
</div>
<div class="wel-card finance-panel">
<div class="panel-title">
营业收支对比
<span class="panel-title__unit">万元</span>
</div>
<wel-chart :option="barOpt" height="300px" />
</div>
<div class="wel-card finance-panel">
<div class="panel-title">
主营业务收入/费用趋势
<span class="panel-title__unit">万元</span>
</div>
<wel-chart :option="lineOpt" height="280px" />
</div>
</section>
</template>
<script>
import WelChart from './wel-chart.vue';
import WelFilters from './wel-filters.vue';
import { groupBarOption, lineAreaOption } from '../chart-options';
export default {
name: 'section-finance',
components: { WelChart, WelFilters },
data() {
const months = Array.from({ length: 12 }, (_, i) => `${i + 1}月`);
return {
months,
// Mock:财务收支数据,对接统计接口后替换
incomeData: [2860, 1520, 1180, 1150, 980, 920, 760, 720, 690, 520, 380, 260],
costData: [2410, 1330, 1010, 980, 850, 800, 660, 630, 610, 470, 340, 230],
trendIncome: [1780, 1850, 1810, 1880, 1920, 1950, 1720, 1650, 1830, 1900, 1980, 2060],
trendCost: [1520, 1560, 1540, 1590, 1610, 1620, 1450, 1400, 1530, 1580, 1640, 1700],
};
},
computed: {
barOpt() {
return groupBarOption(this.months, [
{ name: '收入', data: this.incomeData, color: '#4a90e2' },
{ name: '费用', data: this.costData, color: '#d9dce3' },
]);
},
lineOpt() {
return lineAreaOption(this.months, [
{ name: '主营业务收入', data: this.trendIncome, color: '#4a90e2' },
{ name: '主营业务费用', data: this.trendCost, color: '#2bb3a3' },
]);
},
},
};
</script>
<style lang="scss" scoped>
@import '../dashboard.scss';
.finance-panel {
margin-bottom: 16px;
}
</style>
@@ -0,0 +1,75 @@
<template>
<section class="wel-sec">
<div class="wel-sec__head">
<span class="wel-sec__title">车队与线路</span>
<wel-filters condition-label="运输方式" />
</div>
<el-row :gutter="16">
<el-col :xs="24" :md="12">
<rank-panel
title="下游车队 TOP10"
unit="单"
color="#1a9e94"
:items="fleetItems"
height="320px"
:name-width="120"
class="fleet-panel"
/>
</el-col>
<el-col :xs="24" :md="12">
<rank-panel
title="运输线路 TOP5"
unit="单"
color="#c9a227"
:items="routeItems"
height="320px"
:name-width="120"
class="fleet-panel"
/>
</el-col>
</el-row>
</section>
</template>
<script>
import RankPanel from './rank-panel.vue';
import WelFilters from './wel-filters.vue';
export default {
name: 'section-fleet',
components: { RankPanel, WelFilters },
data() {
return {
// Mock:车队/线路排行数据,对接统计接口后替换
fleetItems: [
{ name: '顺达车队', value: 186.5 },
{ name: '穗联物流车队', value: 158.2 },
{ name: '宏运车队', value: 132.6 },
{ name: '桂海运输车队', value: 118.4 },
{ name: '南北快运车队', value: 96.7 },
{ name: '恒通货运车队', value: 85.3 },
{ name: '运达车队', value: 74.2 },
{ name: '捷安物流车队', value: 62.8 },
{ name: '广通运输车队', value: 54.6 },
{ name: '长顺车队', value: 43.1 },
],
routeItems: [
{ name: '南宁 → 柳州', value: 342.5 },
{ name: '钦州港 → 南宁', value: 285.6 },
{ name: '贵港 → 广州', value: 226.3 },
{ name: '桂林 → 南宁', value: 168.2 },
{ name: '玉林 → 深圳', value: 142.6 },
],
};
},
};
</script>
<style lang="scss" scoped>
@import '../dashboard.scss';
.fleet-panel {
margin-bottom: 16px;
}
</style>
+183
View File
@@ -0,0 +1,183 @@
<template>
<section class="wel-sec">
<div class="wel-sec__head">
<span class="wel-sec__title">核心经营指标</span>
<wel-filters />
</div>
<el-row :gutter="16">
<el-col v-for="card in cards" :key="card.label" :xs="24" :md="8">
<div class="kpi-card">
<div class="kpi-card__top">
<span class="kpi-card__label">{{ card.label }}</span>
<span
class="kpi-card__badge"
:class="card.trend >= 0 ? 'is-up' : 'is-down'"
>
环比 {{ card.trend >= 0 ? '+' : '' }}{{ card.trend }}%
</span>
</div>
<div class="kpi-card__value">
{{ card.value }}<span class="kpi-card__unit">{{ card.unit }}</span>
</div>
<ul class="kpi-card__subs">
<li v-for="s in card.subs" :key="s.name">
<span class="kpi-card__sub-name">{{ s.name }}</span>
<span class="kpi-card__sub-value">{{ s.value }}</span>
<span
v-if="typeof s.change === 'number'"
class="kpi-card__sub-change"
:class="s.change >= 0 ? 'is-up' : 'is-down'"
>
{{ s.change >= 0 ? '↑' : '↓' }} {{ Math.abs(s.change) }}%
</span>
</li>
</ul>
</div>
</el-col>
</el-row>
</section>
</template>
<script>
import WelFilters from './wel-filters.vue';
export default {
name: 'section-kpi',
components: { WelFilters },
data() {
return {
// Mock:营业额/运单量/利润等核心指标,对接统计接口后替换
cards: [
{
label: '营业额',
value: '58,814.0',
unit: '万元',
trend: 12.6,
subs: [
{ name: '毛利率', value: '23.5%', change: 1.2 },
{ name: '运输成本', value: '45,031 万元', change: -0.8 },
{ name: '回款金额', value: '39,640 万元', change: 3.4 },
{ name: '应收账款', value: '19,174 万元', change: -2.1 },
],
},
{
label: '运单量',
value: '1,497.1',
unit: '单',
trend: 8.4,
subs: [
{ name: '已完成', value: '1,205 单', change: 6.2 },
{ name: '在途', value: '135 单', change: 12.0 },
{ name: '待发运', value: '92 单', change: -4.5 },
{ name: '异常单', value: '65 单', change: 1.8 },
],
},
{
label: '运输利润',
value: '2,058.2',
unit: '万元',
trend: 15.7,
subs: [
{ name: '利润率', value: '13.7%', change: 1.5 },
{ name: '单均利润', value: '1.38 万元', change: 5.6 },
{ name: '燃油成本', value: '8,931 万元', change: -3.2 },
{ name: '过路费用', value: '4,208 万元', change: 0.9 },
],
},
],
};
},
};
</script>
<style lang="scss" scoped>
@import '../dashboard.scss';
.kpi-card {
background: #ffffff;
border-radius: 10px;
padding: 18px 20px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
margin-bottom: 16px;
}
.kpi-card__top {
display: flex;
align-items: center;
justify-content: space-between;
}
.kpi-card__label {
font-size: 13px;
color: #909399;
}
.kpi-card__badge {
font-size: 12px;
padding: 2px 8px;
border-radius: 10px;
&.is-up {
color: #f04747;
background: #fdecec;
}
&.is-down {
color: #2ba471;
background: #e8f7ef;
}
}
.kpi-card__value {
font-size: 30px;
font-weight: 700;
color: #303133;
margin: 8px 0 12px;
}
.kpi-card__unit {
font-size: 13px;
font-weight: 400;
color: #909399;
margin-left: 6px;
}
.kpi-card__subs {
list-style: none;
margin: 0;
padding: 10px 0 0;
border-top: 1px solid #f0f2f5;
li {
display: flex;
align-items: center;
padding: 5px 0;
font-size: 13px;
}
}
.kpi-card__sub-name {
color: #909399;
flex: 1;
}
.kpi-card__sub-value {
color: #303133;
font-weight: 600;
margin-right: 10px;
}
.kpi-card__sub-change {
width: 56px;
text-align: right;
&.is-up {
color: #f04747;
}
&.is-down {
color: #2ba471;
}
}
</style>
@@ -0,0 +1,70 @@
<template>
<section class="wel-sec">
<div class="wel-sec__head">
<span class="wel-sec__title">项目情况</span>
<wel-filters condition-label="项目状态" />
</div>
<el-row :gutter="16">
<el-col :xs="24" :md="12">
<rank-panel
title="项目收入 TOP5"
unit="万元"
color="#8b5cf6"
:items="incomeItems"
height="280px"
:name-width="180"
class="project-panel"
/>
</el-col>
<el-col :xs="24" :md="12">
<rank-panel
title="项目运量 TOP5"
unit="万吨"
color="#2bb3a3"
:items="volumeItems"
height="280px"
:name-width="180"
class="project-panel"
/>
</el-col>
</el-row>
</section>
</template>
<script>
import RankPanel from './rank-panel.vue';
import WelFilters from './wel-filters.vue';
export default {
name: 'section-project',
components: { RankPanel, WelFilters },
data() {
return {
// Mock:项目排行数据,对接统计接口后替换
incomeItems: [
{ name: '广西华谊氯碱化工物流项目', value: 1285.6 },
{ name: '柳钢集团钢材外运项目(二期)', value: 982.4 },
{ name: '南宁轨道交通建材配送项目', value: 756.3 },
{ name: '北部湾港集装箱短驳项目', value: 621.7 },
{ name: '中粮集团粮食储备调运项目', value: 468.2 },
],
volumeItems: [
{ name: '广西华谊氯碱化工物流项目', value: 32.5 },
{ name: '柳钢集团钢材外运项目(二期)', value: 26.8 },
{ name: '南宁轨道交通建材配送项目', value: 21.4 },
{ name: '北部湾港集装箱短驳项目', value: 18.6 },
{ name: '中粮集团粮食储备调运项目', value: 15.2 },
],
};
},
};
</script>
<style lang="scss" scoped>
@import '../dashboard.scss';
.project-panel {
margin-bottom: 16px;
}
</style>
@@ -0,0 +1,114 @@
<template>
<section class="wel-sec">
<div class="wel-sec__head">
<span class="wel-sec__title">运输结构</span>
<wel-filters condition-label="业务类型" />
</div>
<!-- 小指标卡 -->
<el-row :gutter="16" class="structure-cards">
<el-col v-for="c in miniCards" :key="c.label" :xs="12" :md="6">
<div class="mini-card structure-cards__item">
<div class="mini-card__label">{{ c.label }}</div>
<div class="mini-card__value">
{{ c.value }}<span class="mini-card__unit">{{ c.unit }}</span>
</div>
<div v-if="typeof c.change === 'number'" class="mini-card__trend" :class="c.change >= 0 ? 'is-up' : 'is-down'">
环比 {{ c.change >= 0 ? '+' : '' }}{{ c.change }}%
</div>
</div>
</el-col>
</el-row>
<!-- 三个占比环形图 -->
<el-row :gutter="16">
<el-col v-for="d in donuts" :key="d.title" :xs="24" :md="8">
<div class="wel-card donut-panel">
<div class="panel-title">
{{ d.title }}
<span class="panel-title__unit">{{ d.unit }}</span>
</div>
<wel-chart :option="donutOpt(d)" height="230px" />
</div>
</el-col>
</el-row>
</section>
</template>
<script>
import WelChart from './wel-chart.vue';
import WelFilters from './wel-filters.vue';
import { donutOption } from '../chart-options';
export default {
name: 'section-structure',
components: { WelChart, WelFilters },
data() {
return {
// Mock:运输结构统计,对接统计接口后替换
miniCards: [
{ label: '总运单量', value: '1,391', unit: '单', change: 30 },
{ label: '在途运单', value: '487', unit: '单', change: 12.5 },
{ label: '待发运', value: '135', unit: '单', change: -6.3 },
{ label: '总运量', value: '15.2', unit: '万吨', change: 8.1 },
],
donuts: [
{
title: '运输方式占比',
unit: '按运单量',
centerTitle: '1,391',
centerSub: '总运单(单)',
items: [
{ name: '公路', value: 620 },
{ name: '铁路', value: 335 },
{ name: '水运', value: 215 },
{ name: '航空', value: 121 },
{ name: '多式联运', value: 100 },
],
},
{
title: '货物类型占比',
unit: '按运量',
centerTitle: '15.2',
centerSub: '总运量(万吨)',
items: [
{ name: '普货', value: 6.4 },
{ name: '冷链', value: 3.2 },
{ name: '大件', value: 2.6 },
{ name: '危险品', value: 1.8 },
{ name: '其他', value: 1.2 },
],
},
{
title: '客户类型占比',
unit: '按运单量',
centerTitle: '326',
centerSub: '合作客户(家)',
items: [
{ name: '合同客户', value: 810 },
{ name: '散单客户', value: 372 },
{ name: '平台客户', value: 209 },
],
},
],
};
},
methods: {
donutOpt(d) {
return donutOption(d.items, { centerTitle: d.centerTitle, centerSub: d.centerSub });
},
},
};
</script>
<style lang="scss" scoped>
@import '../dashboard.scss';
.structure-cards__item {
margin-bottom: 16px;
}
.donut-panel {
margin-bottom: 16px;
}
</style>
@@ -0,0 +1,67 @@
<template>
<section class="wel-sec">
<el-row :gutter="16">
<el-col :xs="24" :md="12">
<div class="wel-card summary-panel">
<div class="panel-title">
车辆耗时占比
<span class="panel-title__unit">按小时</span>
</div>
<wel-chart :option="donutOpt" height="260px" />
</div>
</el-col>
<el-col :xs="24" :md="12">
<div class="wel-card summary-panel">
<div class="panel-title">
单据完成趋势
<span class="panel-title__unit">按周</span>
</div>
<wel-chart :option="lineOpt" height="260px" />
</div>
</el-col>
</el-row>
</section>
</template>
<script>
import WelChart from './wel-chart.vue';
import { donutOption, lineAreaOption } from '../chart-options';
export default {
name: 'section-summary',
components: { WelChart },
data() {
return {
// Mock:车辆耗时与单据完成数据,对接统计接口后替换
timeItems: [
{ name: '在途运输', value: 86.2 },
{ name: '装货等待', value: 32.5 },
{ name: '卸货作业', value: 28.4 },
{ name: '返程空驶', value: 21.6 },
{ name: '场站等待', value: 18.3 },
{ name: '维修保养', value: 9.8 },
],
weeks: ['1周', '2周', '3周', '4周', '5周', '6周', '7周'],
doneData: [520, 545, 508, 532, 560, 548, 572],
};
},
computed: {
donutOpt() {
return donutOption(this.timeItems, { centerTitle: '196.8', centerSub: '总耗时(小时)' });
},
lineOpt() {
return lineAreaOption(this.weeks, [
{ name: '完成单据', data: this.doneData, color: '#1a9e94' },
]);
},
},
};
</script>
<style lang="scss" scoped>
@import '../dashboard.scss';
.summary-panel {
margin-bottom: 16px;
}
</style>
@@ -0,0 +1,76 @@
<template>
<section class="wel-sec">
<div class="wel-sec__head">
<span class="wel-sec__title">车务管理</span>
<wel-filters condition-label="车辆类型" />
</div>
<!-- 车务小指标卡 -->
<el-row :gutter="16" class="vehicle-cards">
<el-col v-for="c in miniCards" :key="c.label" :xs="12" :md="6">
<div class="mini-card vehicle-cards__item">
<div class="mini-card__label">{{ c.label }}</div>
<div class="mini-card__value">
{{ c.value }}<span class="mini-card__unit">{{ c.unit }}</span>
</div>
<div v-if="typeof c.change === 'number'" class="mini-card__trend" :class="c.change >= 0 ? 'is-up' : 'is-down'">
环比 {{ c.change >= 0 ? '+' : '' }}{{ c.change }}%
</div>
</div>
</el-col>
</el-row>
<!-- 车辆耗费构成堆叠柱状图 -->
<div class="wel-card">
<div class="panel-title">
车辆耗费构成
<span class="panel-title__unit">万元</span>
</div>
<wel-chart :option="stackOpt" height="320px" />
</div>
</section>
</template>
<script>
import WelChart from './wel-chart.vue';
import WelFilters from './wel-filters.vue';
import { stackBarOption } from '../chart-options';
export default {
name: 'section-vehicle',
components: { WelChart, WelFilters },
data() {
const months = Array.from({ length: 12 }, (_, i) => `${i + 1}月`);
return {
months,
// Mock:车务统计与耗费数据,对接统计接口后替换
miniCards: [
{ label: '可用车辆', value: 47, unit: '辆', change: 4.2 },
{ label: '维修保养中', value: 7, unit: '辆', change: -8.6 },
{ label: '年检临期', value: 9, unit: '辆', change: 12.5 },
{ label: '违章未处理', value: 12, unit: '起', change: -2.1 },
],
fuelData: [68, 52, 41, 36, 32, 38, 24, 46, 38, 28, 12, 14],
repairData: [22, 25, 18, 20, 16, 18, 14, 12, 15, 11, 6, 8],
otherData: [15, 14, 12, 13, 11, 12, 9, 11, 10, 8, 5, 6],
};
},
computed: {
stackOpt() {
return stackBarOption(this.months, [
{ name: '油费', data: this.fuelData, color: '#e0b14c' },
{ name: '维修保养', data: this.repairData, color: '#58b98a' },
{ name: '其他费用', data: this.otherData, color: '#4a90e2' },
]);
},
},
};
</script>
<style lang="scss" scoped>
@import '../dashboard.scss';
.vehicle-cards__item {
margin-bottom: 16px;
}
</style>
+57
View File
@@ -0,0 +1,57 @@
<template>
<div ref="chartEl" class="wel-chart" :style="{ height: height }"></div>
</template>
<script>
import * as echarts from 'echarts';
export default {
name: 'wel-chart',
props: {
option: { type: Object, required: true },
height: { type: String, default: '260px' },
},
data() {
return {
chart: null,
resizeObserver: null,
};
},
watch: {
option: {
deep: true,
handler() {
this.render();
},
},
},
mounted() {
this.chart = echarts.init(this.$refs.chartEl);
this.render();
this.resizeObserver = new ResizeObserver(() => {
this.chart && this.chart.resize();
});
this.resizeObserver.observe(this.$refs.chartEl);
},
activated() {
/* keep-alive 恢复时重算尺寸 */
this.chart && this.chart.resize();
},
beforeUnmount() {
this.resizeObserver && this.resizeObserver.disconnect();
this.chart && this.chart.dispose();
this.chart = null;
},
methods: {
render() {
this.chart && this.chart.setOption(this.option, true);
},
},
};
</script>
<style lang="scss" scoped>
.wel-chart {
width: 100%;
}
</style>
+49
View File
@@ -0,0 +1,49 @@
<template>
<div class="wel-filter">
<span class="wel-filter__label">统计时间</span>
<el-select v-model="year" size="small">
<el-option v-for="y in yearOptions" :key="y" :label="y + '年'" :value="y" />
</el-select>
<el-select v-model="range" size="small" class="wel-filter__range">
<el-option v-for="r in rangeOptions" :key="r.value" :label="r.label" :value="r.value" />
</el-select>
<template v-if="conditionLabel">
<span class="wel-filter__label">{{ conditionLabel }}</span>
<el-select v-model="condition" size="small">
<el-option label="全部" value="all" />
</el-select>
</template>
</div>
</template>
<script>
export default {
name: 'wel-filters',
props: {
conditionLabel: { type: String, default: '' },
},
data() {
const now = new Date().getFullYear();
return {
year: now,
yearOptions: [now, now - 1, now - 2, now - 3],
range: 'year',
rangeOptions: [
{ label: '全年', value: 'year' },
{ label: '上半年', value: 'h1' },
{ label: '下半年', value: 'h2' },
{ label: '自定义', value: 'custom' },
],
condition: 'all',
};
},
};
</script>
<style lang="scss" scoped>
@import '../dashboard.scss';
.wel-filter__range {
width: 110px;
}
</style>