472 lines
16 KiB
Vue
472 lines
16 KiB
Vue
|
<template>
|
||
|
<div id="PlanSchedule" :style="{top: top+'px', height: height+'px'}">
|
||
|
<div class="left">
|
||
|
<div :id="runPlanId" />
|
||
|
</div>
|
||
|
<div class="right">
|
||
|
<data-table
|
||
|
ref="serviceTable"
|
||
|
:height="height/2"
|
||
|
:config="serviceNumberConfig"
|
||
|
:style="{top: top-height/2+'px'}"
|
||
|
@touch="scheduleTouch"
|
||
|
/>
|
||
|
<data-table
|
||
|
ref="tripTable"
|
||
|
:height="height/2"
|
||
|
:config="tripNumberConfig"
|
||
|
:style="{top: top-height/2+'px'}"
|
||
|
@touch="trainNumTouch"
|
||
|
/>
|
||
|
</div>
|
||
|
</div>
|
||
|
</template>
|
||
|
|
||
|
<script>
|
||
|
import { mapGetters } from 'vuex';
|
||
|
import { timeFormat } from '@/utils/date';
|
||
|
import { runDiagramGetTime } from '@/api/simulation';
|
||
|
import DataTable from '../menusPlan/components/dataTable';
|
||
|
import echarts from 'echarts';
|
||
|
|
||
|
export default {
|
||
|
name: 'PlanSchedule',
|
||
|
components: {
|
||
|
DataTable
|
||
|
},
|
||
|
props: {
|
||
|
group: {
|
||
|
type: String,
|
||
|
required: true
|
||
|
},
|
||
|
lineCode: {
|
||
|
type: String,
|
||
|
required: true
|
||
|
},
|
||
|
maxWidth: {
|
||
|
type: Number,
|
||
|
require: true
|
||
|
},
|
||
|
maxHeight: {
|
||
|
type: Number,
|
||
|
required: true
|
||
|
}
|
||
|
},
|
||
|
data() {
|
||
|
return {
|
||
|
top: 0,
|
||
|
height: 0,
|
||
|
heights: [100, 100],
|
||
|
runPlanId: 'plan-schedule-id',
|
||
|
myChart: null,
|
||
|
PlanConvert: {},
|
||
|
serviceNumberConfig: {
|
||
|
data: [],
|
||
|
highlightCurrentRow: true,
|
||
|
handleChange: this.serviceNumberChange,
|
||
|
showClose: false,
|
||
|
columns: [
|
||
|
{
|
||
|
prop: 'serviceNumber',
|
||
|
label: '表号'
|
||
|
},
|
||
|
{
|
||
|
width: 40
|
||
|
}
|
||
|
]
|
||
|
},
|
||
|
tripNumberConfig: {
|
||
|
data: [],
|
||
|
highlightCurrentRow: true,
|
||
|
handleChange: this.tripNumberChange,
|
||
|
showClose: false,
|
||
|
columns: [
|
||
|
{
|
||
|
prop: 'tripNumber',
|
||
|
label: '车次号'
|
||
|
},
|
||
|
{
|
||
|
width: 40
|
||
|
}
|
||
|
]
|
||
|
},
|
||
|
realData: {},
|
||
|
kmRangeCoordMap: {},
|
||
|
option: {
|
||
|
title: {
|
||
|
text: '',
|
||
|
left: 'center'
|
||
|
},
|
||
|
grid: {
|
||
|
top: '30px',
|
||
|
left: '120px',
|
||
|
right: '40px',
|
||
|
bottom: '65px',
|
||
|
containLabel: true,
|
||
|
backgroundColor: 'floralwhite'
|
||
|
},
|
||
|
toolbox: {
|
||
|
right: '30px',
|
||
|
feature: {
|
||
|
dataZoom: {
|
||
|
yAxisIndex: 'none'
|
||
|
},
|
||
|
restore: {},
|
||
|
saveAsImage: {}
|
||
|
}
|
||
|
},
|
||
|
tooltip: {
|
||
|
axisPointer: {
|
||
|
trigger: 'item',
|
||
|
type: 'cross'
|
||
|
},
|
||
|
formatter: this.axisTooltip,
|
||
|
borderWidth: 1
|
||
|
},
|
||
|
xAxis: [
|
||
|
{
|
||
|
type: 'category',
|
||
|
boundaryGap: false,
|
||
|
data: [],
|
||
|
axisLine: {
|
||
|
onZero: false,
|
||
|
lineStyle: {
|
||
|
width: 2,
|
||
|
color: '#d14a61'
|
||
|
}
|
||
|
},
|
||
|
axisLabel: {
|
||
|
formatter: this.xAxisLableFormat,
|
||
|
textStyle: {
|
||
|
color: '#333'
|
||
|
}
|
||
|
},
|
||
|
axisPointer: {
|
||
|
snap: true,
|
||
|
label: {
|
||
|
formatter: this.xAxisPointFormat,
|
||
|
backgroundColor: 'rgb(255,0,0,0.5)',
|
||
|
color: 'white'
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
],
|
||
|
yAxis: {
|
||
|
type: 'value',
|
||
|
splitLine: {
|
||
|
show: false
|
||
|
},
|
||
|
axisTick: {
|
||
|
show: false
|
||
|
},
|
||
|
axisLine: {
|
||
|
onZero: false,
|
||
|
lineStyle: {
|
||
|
width: 2,
|
||
|
color: '#d14a61'
|
||
|
}
|
||
|
},
|
||
|
axisLabel: {
|
||
|
interval: 'auto',
|
||
|
formatter: this.yAxisLableFormat
|
||
|
},
|
||
|
axisPointer: {
|
||
|
xAxisIndex: 'all',
|
||
|
label: {
|
||
|
formatter: this.yAxisPointFormat,
|
||
|
backgroundColor: 'rgb(0,100,0,0.5)',
|
||
|
color: 'white'
|
||
|
}
|
||
|
},
|
||
|
min: 0,
|
||
|
max: 0
|
||
|
},
|
||
|
series: [],
|
||
|
dataZoom: [
|
||
|
{
|
||
|
type: 'inside'
|
||
|
},
|
||
|
{
|
||
|
fiterMode: 'filter',
|
||
|
handleIcon: 'M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z',
|
||
|
handleSize: '80%',
|
||
|
handleStyle: {
|
||
|
color: '#fff',
|
||
|
shadowBlur: 3,
|
||
|
shadowColor: 'rgba(0, 0, 0, 0.6)',
|
||
|
shadowOffsetX: 2,
|
||
|
shadowOffsetY: 2
|
||
|
},
|
||
|
bottom: '20px'
|
||
|
}
|
||
|
]
|
||
|
},
|
||
|
absoluteTime: 2 * 3600,
|
||
|
indexKmRangeMap: {}
|
||
|
};
|
||
|
},
|
||
|
computed: {
|
||
|
...mapGetters('runPlan', [
|
||
|
'stations'
|
||
|
])
|
||
|
},
|
||
|
watch: {
|
||
|
maxWidth() {
|
||
|
this.setPosition();
|
||
|
},
|
||
|
maxHeight() {
|
||
|
this.setPosition();
|
||
|
},
|
||
|
'$store.state.runPlan.planLoadedCount': async function () {
|
||
|
await this.loadChartPage();
|
||
|
},
|
||
|
'$store.state.runPlan.planSizeCount': function () {
|
||
|
this.reSize({ width: this.$store.state.runPlan.width, height: this.$store.state.runPlan.height });
|
||
|
},
|
||
|
'$store.state.runPlan.selected.serviceNumber': function (val) {
|
||
|
const index = this.serviceNumberConfig.data.findIndex(elem => {
|
||
|
return elem.serviceNumber == val;
|
||
|
});
|
||
|
|
||
|
this.$refs.serviceTable.setCurrentRow(this.serviceNumberConfig.data[index]);
|
||
|
},
|
||
|
'$store.state.runPlan.selected.tripNumber': function (val) {
|
||
|
const index = this.tripNumberConfig.data.findIndex(elem => {
|
||
|
return elem.tripNumber == val;
|
||
|
});
|
||
|
this.$refs.tripTable.setCurrentRow(this.tripNumberConfig.data[index]);
|
||
|
}
|
||
|
},
|
||
|
mounted() {
|
||
|
this.PlanConvert = this.$theme.loadPlanConvert(this.lineCode);
|
||
|
},
|
||
|
beforeDestroy() {
|
||
|
this.destroy();
|
||
|
},
|
||
|
methods: {
|
||
|
serviceNumberChange(row) {
|
||
|
if (row) {
|
||
|
this.$store.dispatch('runPlan/setSelected', { serviceNumber: row.serviceNumber, tripNumber: null });
|
||
|
const serviceObj = this.$store.state.runPlan.editData[row.serviceNumber];
|
||
|
if (serviceObj) {
|
||
|
this.analyticalTripNumber(serviceObj.trainMap);
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
tripNumberChange(row) {
|
||
|
if (row) {
|
||
|
this.$store.dispatch('runPlan/setSelected', { serviceNumber: this.$store.state.runPlan.selected.serviceNumber, tripNumber: row.tripNumber });
|
||
|
}
|
||
|
},
|
||
|
async analyticalServiceNumber(data) {
|
||
|
this.serviceNumberConfig.data = Object.keys(data || {})
|
||
|
.sort((a, b) => { return data[a].oldIndex - data[b].oldIndex; })
|
||
|
.map(serviceNumber => { return { serviceNumber }; });
|
||
|
},
|
||
|
async analyticalTripNumber(data) {
|
||
|
this.tripNumberConfig.data = Object.keys(data || {})
|
||
|
.sort((a, b) => { return data[a].oldIndex - data[b].oldIndex; })
|
||
|
.map(tripNumber => { return { tripNumber }; });
|
||
|
},
|
||
|
async setPosition() {
|
||
|
this.$nextTick(() => {
|
||
|
let top = 3;
|
||
|
const width = this.maxWidth * 0.85;
|
||
|
let height = this.maxHeight;
|
||
|
|
||
|
const titleBar = document.getElementById('PlanTitleBar');
|
||
|
const menuBar = document.getElementById('PlanMenuBar');
|
||
|
const menuTool = document.getElementById('PlanMenuTool');
|
||
|
const statusBar = document.getElementById('PlanStatusBar');
|
||
|
|
||
|
if (titleBar) {
|
||
|
top += (titleBar.offsetHeight || 0);
|
||
|
}
|
||
|
|
||
|
if (menuBar) {
|
||
|
top += (menuBar.offsetHeight || 0);
|
||
|
}
|
||
|
|
||
|
if (menuTool) {
|
||
|
top += (menuTool.offsetHeight || 0);
|
||
|
}
|
||
|
|
||
|
if (statusBar) {
|
||
|
height -= (statusBar.offsetHeight || 0);
|
||
|
}
|
||
|
|
||
|
height = height - top;
|
||
|
this.$store.dispatch('runPlan/resize', { width, height });
|
||
|
|
||
|
if (this.top != top) {
|
||
|
this.top = top;
|
||
|
}
|
||
|
|
||
|
if (this.height != height) {
|
||
|
this.height = height - 20 * 2;
|
||
|
}
|
||
|
});
|
||
|
},
|
||
|
async loadChartPage() {
|
||
|
try {
|
||
|
let series = [];
|
||
|
const stations = this.$store.state.runPlan.stations;
|
||
|
const planData = this.$store.state.runPlan.planData;
|
||
|
|
||
|
this.viewDisabled = true;
|
||
|
this.kmRangeCoordMap = this.PlanConvert.convertStationsToMap(stations);
|
||
|
series = this.pushModels(series, [this.PlanConvert.initializeYaxis(stations)]);
|
||
|
series = this.pushModels(series, this.PlanConvert.convertDataToModels(planData, stations, this.kmRangeCoordMap, { color: '#000', width: 0.5 }));
|
||
|
await this.loadInitData(series);
|
||
|
await this.analyticalServiceNumber(this.$store.state.runPlan.editData);
|
||
|
this.viewDisabled = false;
|
||
|
|
||
|
} catch (error) {
|
||
|
this.viewDisabled = false;
|
||
|
this.$messageBox(`加载运行图数据失败`);
|
||
|
}
|
||
|
},
|
||
|
async loadInitData(series) {
|
||
|
this.myChart && this.myChart.showLoading();
|
||
|
await this.xAxisInit();
|
||
|
await this.yAxisInit();
|
||
|
await this.loadInitChart(series);
|
||
|
this.myChart && this.myChart.hideLoading();
|
||
|
},
|
||
|
pushModels(series, models) {
|
||
|
if (models && models.length) {
|
||
|
models.forEach(elem => {
|
||
|
if (elem) {
|
||
|
series.push(elem);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
return series;
|
||
|
},
|
||
|
loadInitChart(series) {
|
||
|
return new Promise((resolve, reject) => {
|
||
|
try {
|
||
|
this.destroy();
|
||
|
|
||
|
let startValue = 3600 + this.PlanConvert.TranslationTime;
|
||
|
const offsetTime = 3600;
|
||
|
|
||
|
runDiagramGetTime(this.group).then(resp => {
|
||
|
startValue = resp.data - this.PlanConvert.TranslationTime;
|
||
|
this.option.dataZoom[0].startValue = this.option.dataZoom[1].startValue = startValue - offsetTime;
|
||
|
this.option.dataZoom[0].endValue = this.option.dataZoom[1].endValue = startValue + offsetTime;
|
||
|
this.option.series = series;
|
||
|
this.myChart = echarts.init(document.getElementById(this.runPlanId));
|
||
|
if (this.myChart) {
|
||
|
this.myChart.setOption(this.option);
|
||
|
this.reSize({ width: this.$store.state.runPlan.width, height: this.$store.state.runPlan.height });
|
||
|
this.myChart.on('click', this.mouseClick);
|
||
|
}
|
||
|
});
|
||
|
resolve(true);
|
||
|
} catch (error) {
|
||
|
reject(error);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
},
|
||
|
xAxisPointFormat(params) {
|
||
|
return timeFormat(params.value);
|
||
|
},
|
||
|
yAxisPointFormat(params) {
|
||
|
return this.PlanConvert.computedFormatYAxis(this.stations, params);
|
||
|
},
|
||
|
xAxisLableFormat(value, index) {
|
||
|
if (value % 60 === 0) {
|
||
|
return timeFormat(value);
|
||
|
}
|
||
|
},
|
||
|
yAxisLableFormat(value, index) {
|
||
|
return '';
|
||
|
},
|
||
|
xAxisInit() {
|
||
|
const list = [];
|
||
|
for (var time = 0 + this.PlanConvert.TranslationTime; time < 3600 * 24 + this.PlanConvert.TranslationTime; time++) {
|
||
|
list.push(time);
|
||
|
}
|
||
|
|
||
|
const startValue = 3600 * 6;
|
||
|
const offsetTime = 3600 * 1;
|
||
|
|
||
|
this.option.xAxis[0].data = list;
|
||
|
if (!this.option.dataZoom[0].startValue) {
|
||
|
this.option.dataZoom[0].startValue = this.option.dataZoom[1].startValue = startValue - offsetTime;
|
||
|
}
|
||
|
|
||
|
if (!this.option.dataZoom[0].endValue) {
|
||
|
this.option.dataZoom[0].endValue = this.option.dataZoom[1].endValue = startValue + offsetTime;
|
||
|
}
|
||
|
},
|
||
|
yAxisInit() {
|
||
|
if (Object.keys(this.PlanConvert).length) {
|
||
|
this.option.yAxis.min = this.PlanConvert.computedYaxisMinValue(this.stations);
|
||
|
this.option.yAxis.max = this.PlanConvert.computedYaxisMaxValue(this.stations);
|
||
|
}
|
||
|
},
|
||
|
axisTooltip(param) {
|
||
|
const station = this.stations[Math.floor((param.data[1] - this.PlanConvert.EdgeHeight) / this.PlanConvert.CoordMultiple)] || { name: '', kmRange: '' };
|
||
|
return [
|
||
|
`Point Data <hr size=1 style=" margin: 3px 0">`,
|
||
|
`车站名称: ${station.name}<br>`,
|
||
|
`车站公里标: ${station.kmRange} km <br>`,
|
||
|
`到站时间: ${timeFormat(param.data[0] + this.PlanConvert.TranslationTime)} (${param.data[0]})<br>`
|
||
|
].join('');
|
||
|
},
|
||
|
mouseClick(params) {
|
||
|
const model = {
|
||
|
serviceNumber: params.seriesName
|
||
|
};
|
||
|
this.$store.dispatch('runPlan/setSelected', model);
|
||
|
},
|
||
|
reSize(opt) {
|
||
|
if (this.myChart) {
|
||
|
this.myChart.resize({
|
||
|
width: opt.width,
|
||
|
height: opt.height,
|
||
|
silent: false
|
||
|
});
|
||
|
}
|
||
|
},
|
||
|
destroy() {
|
||
|
if (this.myChart && this.myChart.isDisposed) {
|
||
|
this.myChart.dispose();
|
||
|
this.myChart = null;
|
||
|
}
|
||
|
},
|
||
|
scheduleTouch() {
|
||
|
|
||
|
},
|
||
|
trainNumTouch() {
|
||
|
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
</script>
|
||
|
<style scoped rel="stylesheet/scss" lang="scss">
|
||
|
@import "src/styles/mixin.scss";
|
||
|
|
||
|
#PlanSchedule {
|
||
|
z-index: 5;
|
||
|
position: absolute;
|
||
|
width: 100%;
|
||
|
|
||
|
.left {
|
||
|
height: 100%;
|
||
|
width: 85%;
|
||
|
float: left;
|
||
|
}
|
||
|
|
||
|
.right {
|
||
|
height: 100%;
|
||
|
width: 15%;
|
||
|
float: right;
|
||
|
}
|
||
|
}
|
||
|
</style>
|