mirror of
https://github.com/Spythere/pojazdownik.git
synced 2026-05-03 11:45:34 +00:00
Wersja 1.3.0
Merge do wersji 1.3.0
This commit is contained in:
+1
-2
@@ -1,5 +1,5 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="pl">
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
@@ -7,7 +7,6 @@
|
|||||||
|
|
||||||
<title>Pojazdownik</title>
|
<title>Pojazdownik</title>
|
||||||
<meta name="description" content="Edytor pociągów online do symulatora Train Driver 2" />
|
<meta name="description" content="Edytor pociągów online do symulatora Train Driver 2" />
|
||||||
<meta name="keywords" content="pojazdownik td2 train driver stacjownik spythere" />
|
|
||||||
|
|
||||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
||||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
|
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "pojazdownik",
|
"name": "pojazdownik",
|
||||||
"version": "1.2.3",
|
"version": "1.3.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 932 B |
Binary file not shown.
|
After Width: | Height: | Size: 953 B |
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1020 B |
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
+14
-17
@@ -34,6 +34,7 @@
|
|||||||
regulaminem symulatora Train Driver 2</a
|
regulaminem symulatora Train Driver 2</a
|
||||||
>!
|
>!
|
||||||
</div>
|
</div>
|
||||||
|
<div class="text--grayed" style="margin-bottom: 0.25em">Strona jest kompletna dla wersji 2022.2.2 symulatora TD2</div>
|
||||||
©
|
©
|
||||||
<a href="https://td2.info.pl/profile/?u=20777" target="_blank">Spythere</a>
|
<a href="https://td2.info.pl/profile/?u=20777" target="_blank">Spythere</a>
|
||||||
{{ new Date().getUTCFullYear() }} | v{{ VERSION }}
|
{{ new Date().getUTCFullYear() }} | v{{ VERSION }}
|
||||||
@@ -46,13 +47,13 @@ import packageInfo from '.././package.json';
|
|||||||
|
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
|
|
||||||
import InputsSection from './components/InputsSection.vue';
|
import InputsSection from './components/sections/InputsSection.vue';
|
||||||
|
|
||||||
import { useStore } from './store';
|
import { useStore } from './store';
|
||||||
import TrainImageSection from './components/TrainImageSection.vue';
|
import TrainImageSection from './components/sections/TrainImageSection.vue';
|
||||||
import LogoSection from './components/LogoSection.vue';
|
import LogoSection from './components/sections/LogoSection.vue';
|
||||||
import RealStockCard from './components/cards/RealStockCard.vue';
|
import RealStockCard from './components/cards/RealStockCard.vue';
|
||||||
import StockSection from './components/StockSection.vue';
|
import StockSection from './components/sections/StockSection.vue';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
@@ -70,7 +71,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
async created() {
|
async created() {
|
||||||
const stockData = await (
|
const stockData = await (
|
||||||
await fetch(`https://spythere.github.io/api/td2/data/stockData.json?t=${Math.floor(Date.now() / 60000)}`)
|
await fetch(`https://spythere.github.io/api/td2/data/stockInfo.json?t=${Math.floor(Date.now() / 60000)}`)
|
||||||
).json();
|
).json();
|
||||||
|
|
||||||
this.store.stockData = stockData;
|
this.store.stockData = stockData;
|
||||||
@@ -86,7 +87,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding: 1em;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* APP */
|
/* APP */
|
||||||
@@ -95,9 +96,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
color: $textColor;
|
color: $textColor;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
|
padding: 1em 0.5em;
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* HEADER SECTION */
|
/* HEADER SECTION */
|
||||||
@@ -145,14 +144,14 @@ main {
|
|||||||
display: grid;
|
display: grid;
|
||||||
gap: 1em 3em;
|
gap: 1em 3em;
|
||||||
|
|
||||||
width: 100vw;
|
width: 100%;
|
||||||
max-width: 1300px;
|
max-width: 1300px;
|
||||||
min-height: 75vh;
|
min-height: 75vh;
|
||||||
|
|
||||||
grid-template-columns: 1fr 2fr;
|
grid-template-columns: 1fr 2fr;
|
||||||
grid-template-rows: auto 360px minmax(400px, 1fr);
|
grid-template-rows: auto 360px minmax(400px, 1fr);
|
||||||
|
|
||||||
padding: 0 1em;
|
// padding: 0 1em;
|
||||||
margin-bottom: 2em;
|
margin-bottom: 2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,6 +166,10 @@ footer {
|
|||||||
/* MOBILE VIEWS */
|
/* MOBILE VIEWS */
|
||||||
|
|
||||||
@media screen and (max-width: $breakpointMd) {
|
@media screen and (max-width: $breakpointMd) {
|
||||||
|
#app {
|
||||||
|
font-size: calc(0.7rem + 0.75vw);
|
||||||
|
}
|
||||||
|
|
||||||
main {
|
main {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -174,11 +177,5 @@ footer {
|
|||||||
grid-template-rows: 1fr;
|
grid-template-rows: 1fr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// @media screen and (max-width: $breakpointSm) {
|
|
||||||
// header {
|
|
||||||
// font-size: 0.75em;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
@@ -1,76 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="stock-section">
|
|
||||||
<transition name="tab-change" mode="out-in">
|
|
||||||
<keep-alive>
|
|
||||||
<component :is="chosenSectionComponent" :key="chosenSectionComponent"></component>
|
|
||||||
</keep-alive>
|
|
||||||
</transition>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
import { useStore } from '../store';
|
|
||||||
import StockListTab from './StockListTab.vue';
|
|
||||||
import StockGeneratorTab from './StockGeneratorTab.vue';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
setup() {
|
|
||||||
return {
|
|
||||||
store: useStore(),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
|
||||||
chosenSectionComponent() {
|
|
||||||
switch (this.store.stockSectionMode) {
|
|
||||||
case 'stock-list':
|
|
||||||
return StockListTab;
|
|
||||||
|
|
||||||
case 'stock-generator':
|
|
||||||
return StockGeneratorTab;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return StockListTab;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
// Tab change animation
|
|
||||||
.tab-change {
|
|
||||||
&-enter-from,
|
|
||||||
&-leave-to {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-enter-active,
|
|
||||||
&-leave-active {
|
|
||||||
transition: all 100ms ease-in-out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Section styles
|
|
||||||
.stock-section {
|
|
||||||
grid-row: 1 / 4;
|
|
||||||
grid-column: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stock tabs styles
|
|
||||||
.stock_actions {
|
|
||||||
display: flex;
|
|
||||||
gap: 0.5em;
|
|
||||||
|
|
||||||
@media only screen and (max-width: 450px) {
|
|
||||||
flex-wrap: wrap;
|
|
||||||
|
|
||||||
button {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
@@ -41,18 +41,18 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { Vehicle, IStock, IReadyStockList } from '../../types';
|
import { Vehicle, IReadyStockList } from '../../types';
|
||||||
|
|
||||||
import { useStore } from '../../store';
|
import { useStore } from '../../store';
|
||||||
import { isLocomotive } from '../../utils/vehicleUtils';
|
|
||||||
import imageMixin from '../../mixins/imageMixin';
|
import imageMixin from '../../mixins/imageMixin';
|
||||||
|
import stockMixin from '../../mixins/stockMixin';
|
||||||
|
|
||||||
interface ResponseJSONData {
|
interface ResponseJSONData {
|
||||||
[key: string]: string;
|
[key: string]: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
mixins: [imageMixin],
|
mixins: [imageMixin, stockMixin],
|
||||||
|
|
||||||
setup() {
|
setup() {
|
||||||
return {
|
return {
|
||||||
@@ -88,60 +88,14 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
choseStock(name: string, type: string, number: string, stockString: string) {
|
choseStock(name: string, type: string, number: string, stockString: string) {
|
||||||
const stockArray = stockString.split(';');
|
this.loadStockFromString(stockString);
|
||||||
|
|
||||||
this.store.stockList.length = 0;
|
|
||||||
this.store.chosenVehicle = null;
|
|
||||||
this.store.chosenCar = null;
|
|
||||||
this.store.chosenCargo = null;
|
|
||||||
this.store.chosenLoco = null;
|
|
||||||
this.store.chosenStockListIndex = -1;
|
|
||||||
|
|
||||||
this.store.swapVehicles = false;
|
|
||||||
|
|
||||||
stockArray.forEach((type, i) => {
|
|
||||||
let vehicle: Vehicle | null = null;
|
|
||||||
if (i == 0) vehicle = this.store.locoDataList.find((loco) => loco.type == stockArray[0]) || null;
|
|
||||||
else vehicle = this.store.carDataList.find((car) => car.type == type) || null;
|
|
||||||
|
|
||||||
this.addVehicle(vehicle);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.store.isRealStockListCardOpen = false;
|
this.store.isRealStockListCardOpen = false;
|
||||||
},
|
},
|
||||||
|
|
||||||
addVehicle(vehicle: Vehicle | null) {
|
|
||||||
if (!vehicle) return;
|
|
||||||
|
|
||||||
const stockObj: IStock = {
|
|
||||||
id: `${Date.now() + this.store.stockList.length}`,
|
|
||||||
type: vehicle.type,
|
|
||||||
length: vehicle.length,
|
|
||||||
mass: vehicle.mass,
|
|
||||||
maxSpeed: vehicle.maxSpeed,
|
|
||||||
isLoco: isLocomotive(vehicle),
|
|
||||||
cargo: undefined,
|
|
||||||
count: 1,
|
|
||||||
imgSrc: vehicle.imageSrc,
|
|
||||||
useType: isLocomotive(vehicle) ? vehicle.power : vehicle.useType,
|
|
||||||
supportersOnly: vehicle.supportersOnly,
|
|
||||||
};
|
|
||||||
|
|
||||||
const previousStock =
|
|
||||||
this.store.stockList.length > 0 ? this.store.stockList[this.store.stockList.length - 1] : null;
|
|
||||||
|
|
||||||
if (previousStock && previousStock.type == vehicle.type) {
|
|
||||||
this.store.stockList[this.store.stockList.length - 1].count++;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.store.stockList.push(stockObj);
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
|
||||||
async mounted() {
|
async mounted() {
|
||||||
const readyStockJSONData: ResponseJSONData = await (
|
const readyStockJSONData: ResponseJSONData = await (
|
||||||
await fetch(`https://spythere.github.io/api/readyStock.json?t=${Math.floor(Date.now() / 60000)}`)
|
await fetch(`https://spythere.github.io/api/td2/data/readyStock.json?t=${Math.floor(Date.now() / 60000)}`)
|
||||||
).json();
|
).json();
|
||||||
|
|
||||||
if (!readyStockJSONData) {
|
if (!readyStockJSONData) {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<div class="vehicle-types locos">
|
<div class="vehicle-types locos">
|
||||||
<button
|
<button
|
||||||
v-for="locoType in locomotiveTypeList"
|
v-for="locoType in locomotiveTypeList"
|
||||||
class="btn--choice"
|
class="btn btn--choice"
|
||||||
:data-selected="locoType.id == store.chosenLocoPower"
|
:data-selected="locoType.id == store.chosenLocoPower"
|
||||||
@click="selectLocoType(locoType.id)"
|
@click="selectLocoType(locoType.id)"
|
||||||
>
|
>
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
<div class="vehicle-types carwagons">
|
<div class="vehicle-types carwagons">
|
||||||
<button
|
<button
|
||||||
v-for="carType in carTypeList"
|
v-for="carType in carTypeList"
|
||||||
class="btn--choice"
|
class="btn btn--choice"
|
||||||
:data-selected="carType.id == store.chosenCarUseType"
|
:data-selected="carType.id == store.chosenCarUseType"
|
||||||
@click="selectCarWagonType(carType.id)"
|
@click="selectCarWagonType(carType.id)"
|
||||||
>
|
>
|
||||||
@@ -85,7 +85,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="input_actions">
|
<div class="input_actions">
|
||||||
<button class="btn" @click="addVehicle">DODAJ NOWY</button>
|
<button class="btn" @click="addVehicle(store.chosenVehicle, store.chosenCargo)">DODAJ NOWY</button>
|
||||||
<button
|
<button
|
||||||
class="btn"
|
class="btn"
|
||||||
@click="switchVehicles"
|
@click="switchVehicles"
|
||||||
@@ -107,11 +107,12 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
|
|
||||||
import { IStock } from '../types';
|
import { IStock } from '../../types';
|
||||||
import imageMixin from '../mixins/imageMixin';
|
import imageMixin from '../../mixins/imageMixin';
|
||||||
import { useStore } from '../store';
|
import { useStore } from '../../store';
|
||||||
import { isLocomotive } from '../utils/vehicleUtils';
|
import { isLocomotive } from '../../utils/vehicleUtils';
|
||||||
import stockPreviewMixin from '../mixins/stockPreviewMixin';
|
import stockPreviewMixin from '../../mixins/stockPreviewMixin';
|
||||||
|
import stockMixin from '../../mixins/stockMixin';
|
||||||
|
|
||||||
interface ILocoType {
|
interface ILocoType {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -120,7 +121,7 @@ interface ILocoType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
mixins: [imageMixin, stockPreviewMixin],
|
mixins: [imageMixin, stockPreviewMixin, stockMixin],
|
||||||
|
|
||||||
data: () => ({
|
data: () => ({
|
||||||
locomotiveTypeList: [
|
locomotiveTypeList: [
|
||||||
@@ -174,7 +175,9 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
addOrSwitchVehicle() {
|
addOrSwitchVehicle() {
|
||||||
if (this.store.chosenStockListIndex == -1) this.addVehicle();
|
if (!this.store.chosenVehicle) return;
|
||||||
|
|
||||||
|
if (this.store.chosenStockListIndex == -1) this.addVehicle(this.store.chosenVehicle, this.store.chosenCargo);
|
||||||
else this.switchVehicles();
|
else this.switchVehicles();
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -211,60 +214,16 @@ export default defineComponent({
|
|||||||
|
|
||||||
this.store.stockList[this.store.chosenStockListIndex] = stockObj;
|
this.store.stockList[this.store.chosenStockListIndex] = stockObj;
|
||||||
},
|
},
|
||||||
|
|
||||||
addVehicle() {
|
|
||||||
const vehicle = this.store.chosenVehicle;
|
|
||||||
|
|
||||||
if (!vehicle) return;
|
|
||||||
|
|
||||||
const stockObj: IStock = {
|
|
||||||
id: `${Date.now()}`,
|
|
||||||
useType: isLocomotive(vehicle) ? vehicle.power : vehicle.useType,
|
|
||||||
type: vehicle.type,
|
|
||||||
length: vehicle.length,
|
|
||||||
mass: vehicle.mass,
|
|
||||||
maxSpeed: vehicle.maxSpeed,
|
|
||||||
isLoco: isLocomotive(vehicle),
|
|
||||||
cargo:
|
|
||||||
!isLocomotive(vehicle) && vehicle.loadable && this.store.chosenCargo ? this.store.chosenCargo : undefined,
|
|
||||||
count: 1,
|
|
||||||
imgSrc: vehicle.imageSrc,
|
|
||||||
supportersOnly: vehicle.supportersOnly,
|
|
||||||
};
|
|
||||||
|
|
||||||
const previousStock =
|
|
||||||
this.store.stockList.length > 0 ? this.store.stockList[this.store.stockList.length - 1] : null;
|
|
||||||
|
|
||||||
if (isLocomotive(vehicle) && previousStock && previousStock.type == vehicle.type) {
|
|
||||||
this.store.stockList[this.store.stockList.length - 1].count++;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
!isLocomotive(vehicle) &&
|
|
||||||
previousStock &&
|
|
||||||
previousStock.type == vehicle.type &&
|
|
||||||
previousStock.cargo?.id == this.store.chosenCargo?.id
|
|
||||||
) {
|
|
||||||
this.store.stockList[this.store.stockList.length - 1].count++;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isLocomotive(vehicle) && this.store.stockList.length > 0 && !this.store.stockList[0].isLoco)
|
|
||||||
this.store.stockList.unshift(stockObj);
|
|
||||||
else this.store.stockList.push(stockObj);
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import '../styles/global';
|
@import '../../styles/global';
|
||||||
|
|
||||||
.inputs-section {
|
.inputs-section {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: center;
|
||||||
|
|
||||||
grid-row: 2;
|
grid-row: 2;
|
||||||
grid-column: 1;
|
grid-column: 1;
|
||||||
@@ -274,11 +233,9 @@ export default defineComponent({
|
|||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn--choice {
|
button.btn--choice {
|
||||||
margin-right: 0.5em;
|
font-size: 0.9em;
|
||||||
font-weight: bold;
|
padding: 0.3em 0.6em;
|
||||||
|
|
||||||
background-color: #444;
|
|
||||||
|
|
||||||
&[data-selected='true'] {
|
&[data-selected='true'] {
|
||||||
background-color: $accentColor;
|
background-color: $accentColor;
|
||||||
@@ -305,15 +262,19 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
.input_actions {
|
.input_actions {
|
||||||
display: flex;
|
display: grid;
|
||||||
flex-wrap: wrap;
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 0.5em;
|
||||||
|
|
||||||
button {
|
button:nth-child(3) {
|
||||||
margin: 0.5em 0.5em 0 0;
|
grid-column: 1 / 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.vehicle-types {
|
.vehicle-types {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.25em;
|
||||||
|
|
||||||
margin-bottom: 0.5em;
|
margin-bottom: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,7 +284,7 @@ export default defineComponent({
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input_actions {
|
.vehicle-types {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
<template>
|
||||||
|
<section class="stock-section">
|
||||||
|
<div class="section_modes">
|
||||||
|
<button
|
||||||
|
class="btn"
|
||||||
|
v-for="(id, name) in sectionModes"
|
||||||
|
@click="chooseSection(id)"
|
||||||
|
:data-selected="store.stockSectionMode == id"
|
||||||
|
>
|
||||||
|
{{ name }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<transition name="tab-change" mode="out-in">
|
||||||
|
<keep-alive>
|
||||||
|
<component :is="chosenSectionComponent" :key="chosenSectionComponent"></component>
|
||||||
|
</keep-alive>
|
||||||
|
</transition>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed, KeepAlive } from 'vue';
|
||||||
|
import { useStore } from '../../store';
|
||||||
|
import StockListTab from '../tabs/StockListTab.vue';
|
||||||
|
import StockGeneratorTab from '../tabs/StockGeneratorTab.vue';
|
||||||
|
import NumberGeneratorTab from '../tabs/NumberGeneratorTab.vue';
|
||||||
|
|
||||||
|
const store = useStore();
|
||||||
|
type SectionMode = typeof store.stockSectionMode;
|
||||||
|
|
||||||
|
const sectionModes: { [key: string]: SectionMode } = {
|
||||||
|
SKŁAD: 'stock-list',
|
||||||
|
'GNR. NUMERU': 'number-generator',
|
||||||
|
'GNR. SKŁADU': 'stock-generator',
|
||||||
|
};
|
||||||
|
|
||||||
|
const chosenSectionComponent = computed(() => {
|
||||||
|
switch (store.stockSectionMode) {
|
||||||
|
case 'stock-list':
|
||||||
|
return StockListTab;
|
||||||
|
|
||||||
|
case 'stock-generator':
|
||||||
|
return StockGeneratorTab;
|
||||||
|
|
||||||
|
case 'number-generator':
|
||||||
|
return NumberGeneratorTab;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return StockListTab;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function chooseSection(sectionId: SectionMode) {
|
||||||
|
store.stockSectionMode = sectionId;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import '../../styles/global.scss';
|
||||||
|
|
||||||
|
// Tab change animation
|
||||||
|
.tab-change {
|
||||||
|
&-enter-from,
|
||||||
|
&-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-enter-active,
|
||||||
|
&-leave-active {
|
||||||
|
transition: all 100ms ease-in-out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Section styles
|
||||||
|
.stock-section {
|
||||||
|
grid-row: 1 / 4;
|
||||||
|
grid-column: 2;
|
||||||
|
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section_modes {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 0.5em;
|
||||||
|
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
|
||||||
|
button {
|
||||||
|
position: relative;
|
||||||
|
border-radius: 0.5em 0.5em 0 0;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
|
||||||
|
content: '';
|
||||||
|
width: 0;
|
||||||
|
height: 2px;
|
||||||
|
transition: all 100ms;
|
||||||
|
background-color: $accentColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-selected='true']::after {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
+4
-6
@@ -54,9 +54,9 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computed, defineComponent } from 'vue';
|
import { computed, defineComponent } from 'vue';
|
||||||
import { useStore } from '../store';
|
import { useStore } from '../../store';
|
||||||
import { isLocomotive } from '../utils/vehicleUtils';
|
import { isLocomotive } from '../../utils/vehicleUtils';
|
||||||
import { ILocomotive, Vehicle } from '../types';
|
import { ILocomotive, Vehicle } from '../../types';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
setup() {
|
setup() {
|
||||||
@@ -83,8 +83,6 @@ export default defineComponent({
|
|||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
chosenVehicle(vehicle: Vehicle, prevVehicle: Vehicle) {
|
chosenVehicle(vehicle: Vehicle, prevVehicle: Vehicle) {
|
||||||
console.log(vehicle);
|
|
||||||
|
|
||||||
if (vehicle && vehicle.type != prevVehicle?.type) {
|
if (vehicle && vehicle.type != prevVehicle?.type) {
|
||||||
this.store.imageLoading = true;
|
this.store.imageLoading = true;
|
||||||
}
|
}
|
||||||
@@ -112,7 +110,7 @@ export default defineComponent({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import '../styles/global.scss';
|
@import '../../styles/global.scss';
|
||||||
|
|
||||||
.train-image-section {
|
.train-image-section {
|
||||||
grid-row: 3;
|
grid-row: 3;
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
<template>
|
||||||
|
<div class="number-generator tab">
|
||||||
|
<div class="tab_header">
|
||||||
|
<h2>GENERATOR NUMERU POCIĄGU</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tab_content">
|
||||||
|
<div class="options">
|
||||||
|
<select v-model="beginRegionName" @change="randomizeTrainNumber">
|
||||||
|
<option :value="null" disabled>Początkowy obszar konstrukcyjny</option>
|
||||||
|
<option v-for="(_, name) in genData.regionNumbers" :value="name">{{ name }}</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select v-model="endRegionName" @change="randomizeTrainNumber">
|
||||||
|
<option :value="null" disabled>Końcowy obszar konstrukcyjny</option>
|
||||||
|
<option v-for="(_, name) in genData.regionNumbers" :value="name">{{ name }}</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select v-model="categoryRules" @change="randomizeTrainNumber">
|
||||||
|
<option :value="null" disabled>Kategoria pociągu</option>
|
||||||
|
<option v-for="(rules, category) in genData.categories" :value="rules">{{ category }}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="generated-number">
|
||||||
|
<span v-if="trainNumber">Wygenerowany numer pociągu: <b class="text--accent">{{ trainNumber }}</b></span>
|
||||||
|
<span v-else>Wybierz obszary konstrukcyjne i kategorię!</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<div class="tab_actions">
|
||||||
|
<button class="btn" @click="randomizeTrainNumber">PRZELOSUJ</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { Ref, ref } from 'vue';
|
||||||
|
|
||||||
|
import genData from '../../constants/numberGeneratorData.json';
|
||||||
|
|
||||||
|
type RegionName = keyof typeof genData.regionNumbers;
|
||||||
|
|
||||||
|
const beginRegionName = ref(null) as Ref<RegionName | null>;
|
||||||
|
const endRegionName = ref(null) as Ref<RegionName | null>;
|
||||||
|
const categoryRules = ref(null) as Ref<string | null>;
|
||||||
|
|
||||||
|
const trainNumber = ref(null) as Ref<string | null>;
|
||||||
|
|
||||||
|
const randomizeTrainNumber = () => {
|
||||||
|
if (beginRegionName.value == null || endRegionName.value == null || categoryRules.value == null) return '';
|
||||||
|
|
||||||
|
let number = '';
|
||||||
|
|
||||||
|
if (beginRegionName.value == endRegionName.value) {
|
||||||
|
const sameRegionsNumbers = genData.sameRegions[beginRegionName.value];
|
||||||
|
const randRegionNumber = sameRegionsNumbers[Math.floor(Math.random() * sameRegionsNumbers.length)];
|
||||||
|
number += randRegionNumber.toString();
|
||||||
|
} else {
|
||||||
|
const beginRegionNumber = genData.regionNumbers[beginRegionName.value];
|
||||||
|
const endRegionNumber = genData.regionNumbers[endRegionName.value];
|
||||||
|
|
||||||
|
number += `${beginRegionNumber}${endRegionNumber}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rulesArray = categoryRules.value.split(';').map((r) => ({
|
||||||
|
index: r.split(':')[0],
|
||||||
|
rule: r.split(':')[1],
|
||||||
|
nums: Number(r.split(':')[2] || '1'),
|
||||||
|
}));
|
||||||
|
|
||||||
|
rulesArray.forEach((r) => {
|
||||||
|
const range = r.rule.split('-');
|
||||||
|
|
||||||
|
if (range.length == 1) number += r.rule;
|
||||||
|
else {
|
||||||
|
const [minRange, maxRange] = range;
|
||||||
|
const randRange = Math.floor(Math.random() * (Number(maxRange) - Number(minRange)) + Number(minRange)).toString();
|
||||||
|
|
||||||
|
number += new Array(Math.abs(randRange.length - r.nums)).fill('0').join('') + randRange;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
trainNumber.value = number;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '../../styles/tab.scss';
|
||||||
|
@import '../../styles/global.scss';
|
||||||
|
|
||||||
|
.options {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.5em;
|
||||||
|
|
||||||
|
select {
|
||||||
|
width: calc(50% - 0.5em);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.generated-number {
|
||||||
|
font-size: 1.3em;
|
||||||
|
font-weight: bold;
|
||||||
|
|
||||||
|
margin: 0.5em 0;
|
||||||
|
padding: 0.5em;
|
||||||
|
background-color: $secondaryColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab_actions {
|
||||||
|
margin-top: 0.5em;
|
||||||
|
|
||||||
|
button {
|
||||||
|
grid-column: 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: $breakpointMd) {
|
||||||
|
.number-generator {
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: $breakpointSm) {
|
||||||
|
.options select {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
@@ -1,58 +1,67 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="stock-generator">
|
<div class="stock-generator tab">
|
||||||
<div class="stock_actions">
|
<div class="tab_header">
|
||||||
<h2>GENERATOR SKŁADU TOWAROWEGO</h2>
|
<h2>GENERATOR SKŁADU TOWAROWEGO</h2>
|
||||||
<button class="btn" @click="() => (store.stockSectionMode = 'stock-list')">POWRÓT DO LISTY ></button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="generator_content">
|
<div class="tab_content">
|
||||||
<h2>WŁAŚCIWOŚCI SKŁADU</h2>
|
<div>
|
||||||
|
<h2>WŁAŚCIWOŚCI SKŁADU</h2>
|
||||||
|
|
||||||
<div class="generator_attributes">
|
<b class="text--accent">
|
||||||
<label>
|
⇐ Dodaj lokomotywę na pierwsze miejsce listy, aby uwzględnić ją przy losowaniu składu!
|
||||||
Maksymalna masa (t)
|
</b>
|
||||||
<input type="number" v-model="maxMass" step="100" max="4000" min="0" />
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<label>
|
<div class="tab_attributes">
|
||||||
Maks. długość (m)
|
<label>
|
||||||
<input type="number" v-model="maxLength" step="25" max="650" min="0" />
|
Maksymalna masa (t)
|
||||||
</label>
|
<input type="number" v-model="maxMass" step="100" max="4000" min="0" />
|
||||||
|
</label>
|
||||||
|
|
||||||
<label>
|
<label>
|
||||||
Maks. liczba wagonów
|
Maks. długość (m)
|
||||||
<input type="number" v-model="maxCarCount" step="1" max="60" min="1" />
|
<input type="number" v-model="maxLength" step="25" max="650" min="0" />
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
Maks. liczba wagonów
|
||||||
|
<input type="number" v-model="maxCarCount" step="1" max="60" min="1" />
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2>ŁADUNEK</h2>
|
<div>
|
||||||
<p>Wybierz ładunki, którymi chcesz wypełnić dostępne wagony:</p>
|
<h2>ŁADUNEK</h2>
|
||||||
|
<b>Wybierz ładunki, którymi chcesz wypełnić dostępne wagony:</b>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="generator_cargo">
|
<div class="generator_cargo">
|
||||||
<button
|
<button
|
||||||
class="btn"
|
class="btn"
|
||||||
:data-chosen="chosenCargoTypes.includes(k as string)"
|
:data-chosen="chosenCargoTypes.includes(k.toString())"
|
||||||
v-for="(v, k) in store.stockData?.generator.cargo"
|
v-for="(v, k) in store.stockData?.generator.cargo"
|
||||||
@click="toggleCargoChosen(k as string, v)"
|
@click="toggleCargoChosen(k.toString(), v)"
|
||||||
>
|
>
|
||||||
{{ k }}
|
{{ k }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2>WAGONY Z WYBRANYMI ŁADUNKAMI</h2>
|
<div>
|
||||||
|
<h2>WAGONY Z WYBRANYMI ŁADUNKAMI</h2>
|
||||||
|
|
||||||
<div class="warning">
|
<div class="generator_warning">
|
||||||
<span v-if="computedChosenCarTypes.size == 0">
|
<span v-if="computedChosenCarTypes.size == 0">
|
||||||
Wybierz co najmniej jeden ładunek, aby zobaczyć wagony, które go posiadają!
|
Wybierz co najmniej jeden ładunek, aby zobaczyć wagony, które go posiadają!
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span v-else>
|
<span v-else>
|
||||||
Wagony posiadające wybrane ładunki. Najedź na nazwę, aby zobaczyć podgląd wagonu. Kliknij, aby wyłączyć z
|
Wagony posiadające wybrane ładunki. Najedź na nazwę, aby zobaczyć podgląd wagonu. Kliknij, aby wyłączyć z
|
||||||
losowania (tylko podświetlone nazwy będą uwzględnione).
|
losowania (tylko podświetlone nazwy będą uwzględnione).
|
||||||
</span>
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="generator_vehicles">
|
<div class="generator_vehicles" v-if="computedChosenCarTypes.size != 0">
|
||||||
<button
|
<button
|
||||||
:data-chosen="true"
|
:data-chosen="true"
|
||||||
:data-excluded="excludedCarTypes.includes(carType)"
|
:data-excluded="excludedCarTypes.includes(carType)"
|
||||||
@@ -64,14 +73,12 @@
|
|||||||
@click="toggleCarExclusion(carType)"
|
@click="toggleCarExclusion(carType)"
|
||||||
>
|
>
|
||||||
{{ carType }}
|
{{ carType }}
|
||||||
|
|
||||||
<!-- <span>X</span> -->
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
<div class="generator_actions">
|
<div class="tab_actions">
|
||||||
<button class="btn" :data-disabled="computedChosenCarTypes.size == 0" @click="generateStock()">
|
<button class="btn" :data-disabled="computedChosenCarTypes.size == 0" @click="generateStock()">
|
||||||
WYGENERUJ
|
WYGENERUJ
|
||||||
</button>
|
</button>
|
||||||
@@ -89,15 +96,16 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { useStore } from '../store';
|
import { useStore } from '../../store';
|
||||||
|
|
||||||
import stockMixin from '../mixins/stockMixin';
|
import stockMixin from '../../mixins/stockMixin';
|
||||||
import { ICargo, ICarWagon } from '../types';
|
import { ICargo, ICarWagon } from '../../types';
|
||||||
|
import warningsMixin from '../../mixins/warningsMixin';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'stock-generator',
|
name: 'stock-generator',
|
||||||
|
|
||||||
mixins: [stockMixin],
|
mixins: [stockMixin, warningsMixin],
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@@ -172,13 +180,16 @@ export default defineComponent({
|
|||||||
return acc;
|
return acc;
|
||||||
}, [] as { constructionType: string; carPool: { carWagon: ICarWagon; cargo?: ICargo }[] }[]);
|
}, [] as { constructionType: string; carPool: { carWagon: ICarWagon; cargo?: ICargo }[] }[]);
|
||||||
|
|
||||||
this.store.stockList.length = this.store.stockList[0]?.isLoco ? 1 : 0;
|
const headingLoco = this.store.stockList[0]?.isLoco ? this.store.stockList[0] : undefined;
|
||||||
|
|
||||||
|
this.store.stockList.length = headingLoco ? 1 : 0;
|
||||||
|
const maxMass = this.store.acceptableMass || this.maxMass;
|
||||||
|
|
||||||
new Array(this.maxCarCount).fill(0).forEach(() => {
|
new Array(this.maxCarCount).fill(0).forEach(() => {
|
||||||
const randomStockType = generatedChosenStockList[~~(Math.random() * generatedChosenStockList.length)];
|
const randomStockType = generatedChosenStockList[~~(Math.random() * generatedChosenStockList.length)];
|
||||||
const {carWagon, cargo} = randomStockType.carPool[~~(Math.random() * randomStockType.carPool.length)];
|
const { carWagon, cargo } = randomStockType.carPool[~~(Math.random() * randomStockType.carPool.length)];
|
||||||
|
|
||||||
if (this.store.totalMass + (cargo?.totalMass || carWagon.mass) > this.maxMass) return;
|
if (this.store.totalMass + (cargo?.totalMass || carWagon.mass) > maxMass) return;
|
||||||
if (this.store.totalLength + carWagon.length > this.maxLength) return;
|
if (this.store.totalLength + carWagon.length > this.maxLength) return;
|
||||||
|
|
||||||
this.addCarWagon(carWagon, cargo);
|
this.addCarWagon(carWagon, cargo);
|
||||||
@@ -226,51 +237,8 @@ export default defineComponent({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import '../styles/global.scss';
|
@import '../../styles/global.scss';
|
||||||
|
@import '../../styles/tab.scss';
|
||||||
.stock_actions {
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
margin: 0;
|
|
||||||
color: white;
|
|
||||||
font-size: 1.35em;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
margin-left: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.stock-generator {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.generator_content {
|
|
||||||
margin-top: 1em;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
margin: 1em 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.generator_attributes {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 1em;
|
|
||||||
|
|
||||||
label {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
input {
|
|
||||||
max-width: 250px;
|
|
||||||
margin-top: 0.5em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.generator_cargo,
|
.generator_cargo,
|
||||||
.generator_vehicles {
|
.generator_vehicles {
|
||||||
@@ -313,36 +281,13 @@ h2 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.generator_vehicles {
|
.tab_content {
|
||||||
margin-top: 1em;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
hr {
|
.generator_warning {
|
||||||
height: 3px;
|
|
||||||
background-color: white;
|
|
||||||
outline: none;
|
|
||||||
|
|
||||||
margin: 15px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.generator_actions {
|
|
||||||
display: grid;
|
|
||||||
gap: 0.5em;
|
|
||||||
grid-template-columns: repeat(3, 1fr);
|
|
||||||
|
|
||||||
button {
|
|
||||||
background-color: #131313;
|
|
||||||
|
|
||||||
padding: 0.5em;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
&[data-disabled] button {
|
|
||||||
opacity: 0.75;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.warning {
|
|
||||||
background-color: $accentColor;
|
background-color: $accentColor;
|
||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
text-align: justify;
|
text-align: justify;
|
||||||
@@ -355,17 +300,6 @@ hr {
|
|||||||
.generator_vehicles {
|
.generator_vehicles {
|
||||||
grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
|
grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
|
||||||
}
|
}
|
||||||
|
|
||||||
.generator_attributes {
|
|
||||||
label {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
input {
|
|
||||||
max-width: 100%;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
@@ -1,78 +1,53 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="stock-list">
|
<section class="stock-list">
|
||||||
<div class="stock_actions">
|
|
||||||
<button class="btn" @click="downloadStock">POBIERZ POCIĄG</button>
|
|
||||||
<button class="btn" @click="resetStock">ZRESETUJ LISTĘ</button>
|
|
||||||
<button class="btn" style="margin-left: auto" @click="shuffleCars">TASUJ WAGONY</button>
|
|
||||||
<button class="btn" @click="store.stockSectionMode = 'stock-generator'">LOSUJ SKŁAD</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="stock_controls" :data-disabled="store.chosenStockListIndex == -1">
|
<div class="stock_controls" :data-disabled="store.chosenStockListIndex == -1">
|
||||||
<b class="no">
|
<b class="no">
|
||||||
POJAZD NR <span class="text--accent">{{ store.chosenStockListIndex + 1 }}</span>
|
POJAZD NR <span class="text--accent">{{ store.chosenStockListIndex + 1 }}</span>
|
||||||
</b>
|
</b>
|
||||||
|
|
||||||
<div class="count">
|
|
||||||
<button
|
|
||||||
class="action-btn"
|
|
||||||
:tabindex="store.chosenStockListIndex == -1 ? -1 : 0"
|
|
||||||
@click="subStock(store.chosenStockListIndex)"
|
|
||||||
>
|
|
||||||
<img :src="getIconURL('sub')" alt="subtract vehicle count" />
|
|
||||||
1
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<input
|
|
||||||
v-if="chosenStockVehicle"
|
|
||||||
v-model="chosenStockVehicle.count"
|
|
||||||
type="number"
|
|
||||||
min="1"
|
|
||||||
name="stock-count"
|
|
||||||
id="stock-count"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<input v-else id="stock-count" type="number" value="0" :tabindex="store.chosenStockListIndex == -1 ? -1 : 0" />
|
|
||||||
|
|
||||||
<button
|
|
||||||
class="action-btn"
|
|
||||||
:tabindex="store.chosenStockListIndex == -1 ? -1 : 0"
|
|
||||||
@click="addStock(store.chosenStockListIndex)"
|
|
||||||
>
|
|
||||||
<img :src="getIconURL('add')" alt="add vehicle count" />
|
|
||||||
1
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button
|
<button
|
||||||
class="action-btn"
|
class="btn"
|
||||||
:tabindex="store.chosenStockListIndex == -1 ? -1 : 0"
|
:tabindex="store.chosenStockListIndex == -1 ? -1 : 0"
|
||||||
@click="moveUpStock(store.chosenStockListIndex)"
|
@click="moveUpStock(store.chosenStockListIndex)"
|
||||||
>
|
>
|
||||||
<img :src="getIconURL('higher')" alt="move up vehicle" />
|
<img :src="getIconURL('higher')" alt="move up vehicle" />
|
||||||
Przenieś wyżej
|
PRZENIEŚ WYŻEJ
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
class="action-btn"
|
class="btn"
|
||||||
:tabindex="store.chosenStockListIndex == -1 ? -1 : 0"
|
:tabindex="store.chosenStockListIndex == -1 ? -1 : 0"
|
||||||
@click="moveDownStock(store.chosenStockListIndex)"
|
@click="moveDownStock(store.chosenStockListIndex)"
|
||||||
>
|
>
|
||||||
<img :src="getIconURL('lower')" alt="move down vehicle" />
|
<img :src="getIconURL('lower')" alt="move down vehicle" />
|
||||||
Przenieś niżej
|
PRZENIEŚ NIŻEJ
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
class="action-btn"
|
class="btn"
|
||||||
:tabindex="store.chosenStockListIndex == -1 ? -1 : 0"
|
:tabindex="store.chosenStockListIndex == -1 ? -1 : 0"
|
||||||
@click="removeStock(store.chosenStockListIndex)"
|
@click="removeStock(store.chosenStockListIndex)"
|
||||||
>
|
>
|
||||||
<img :src="getIconURL('remove')" alt="remove vehicle" />
|
<img :src="getIconURL('remove')" alt="remove vehicle" />
|
||||||
Usuń
|
USUŃ
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="stock_clipboard-text" v-if="store.stockList.length > 0">
|
<div class="stock_actions">
|
||||||
<button class="btn" @click="copyToClipboard">Skopiuj tekst składu do schowka</button>
|
<label class="file-label">
|
||||||
|
<div class="btn">WCZYTAJ</div>
|
||||||
|
<input type="file" @change="uploadStock" ref="conFile" accept=".con,.txt" />
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<button class="btn" :data-disabled="stockIsEmpty" :disabled="stockIsEmpty" @click="downloadStock">POBIERZ</button>
|
||||||
|
|
||||||
|
<button class="btn" :data-disabled="stockIsEmpty" :disabled="stockIsEmpty" @click="copyToClipboard">
|
||||||
|
SKOPIUJ
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button class="btn" :data-disabled="stockIsEmpty" :disabled="stockIsEmpty" @click="resetStock">ZRESETUJ</button>
|
||||||
|
|
||||||
|
<button class="btn" :data-disabled="stockIsEmpty" :disabled="stockIsEmpty" @click="shuffleCars">PRZETASUJ</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="stock_specs">
|
<div class="stock_specs">
|
||||||
@@ -85,9 +60,11 @@
|
|||||||
</b>
|
</b>
|
||||||
|
|
||||||
<span>
|
<span>
|
||||||
Masa: <span class="text--accent">{{ store.totalMass }}t</span> - Długość:
|
Masa: <span class="text--accent">{{ store.totalMass }}t</span> (dopuszczalna:
|
||||||
|
<span class="text--accent">{{ store.acceptableMass ? store.acceptableMass + 't' : '-' }}</span
|
||||||
|
>) - Długość:
|
||||||
<span class="text--accent">{{ store.totalLength }}m</span>
|
<span class="text--accent">{{ store.totalLength }}m</span>
|
||||||
- Vmax pociągu: <span class="text--accent">{{ store.maxStockSpeed }} km/h</span>
|
- vMax: <span class="text--accent">{{ store.maxStockSpeed }} km/h</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -117,13 +94,15 @@
|
|||||||
<div class="warning" v-if="tooManyLocomotives">Ten skład posiada za dużo pojazdów trakcyjnych!</div>
|
<div class="warning" v-if="tooManyLocomotives">Ten skład posiada za dużo pojazdów trakcyjnych!</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<StockThumbnails :onListItemClick="onListItemClick" :onStockImageError="stockImageError" />
|
||||||
|
|
||||||
<!-- Stock list -->
|
<!-- Stock list -->
|
||||||
<ul ref="list">
|
<ul ref="stock_list">
|
||||||
<li v-if="store.stockList.length == 0" class="list-empty">
|
<li v-if="stockIsEmpty" class="list-empty">
|
||||||
<div class="stock-info">Lista pojazdów jest pusta!</div>
|
<div class="stock-info">Lista pojazdów jest pusta!</div>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<transition-group name="stock-list-anim">
|
<TransitionGroup name="stock-list-anim">
|
||||||
<li
|
<li
|
||||||
v-for="(stock, i) in store.stockList"
|
v-for="(stock, i) in store.stockList"
|
||||||
:key="stock.id"
|
:key="stock.id"
|
||||||
@@ -156,29 +135,30 @@
|
|||||||
<span class="stock-info__length"> {{ stock.length }}m </span>
|
<span class="stock-info__length"> {{ stock.length }}m </span>
|
||||||
<span class="stock-info__mass">{{ stock.cargo ? stock.cargo.totalMass : stock.mass }}t </span>
|
<span class="stock-info__mass">{{ stock.cargo ? stock.cargo.totalMass : stock.mass }}t </span>
|
||||||
<span class="stock-info__speed"> {{ stock.maxSpeed }}km/h </span>
|
<span class="stock-info__speed"> {{ stock.maxSpeed }}km/h </span>
|
||||||
|
|
||||||
<span class="stock-info__count"> x{{ stock.count }} </span>
|
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</transition-group>
|
</TransitionGroup>
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import TrainImage from './TrainImageSection.vue';
|
import TrainImage from '../sections/TrainImageSection.vue';
|
||||||
|
|
||||||
import { useStore } from '../store';
|
import { useStore } from '../../store';
|
||||||
import warningsMixin from '../mixins/warningsMixin';
|
import warningsMixin from '../../mixins/warningsMixin';
|
||||||
import imageMixin from '../mixins/imageMixin';
|
import imageMixin from '../../mixins/imageMixin';
|
||||||
import stockPreviewMixin from '../mixins/stockPreviewMixin';
|
import stockPreviewMixin from '../../mixins/stockPreviewMixin';
|
||||||
|
import { IStock } from '../../types';
|
||||||
|
import StockThumbnails from '../utils/StockThumbnails.vue';
|
||||||
|
import stockMixin from '../../mixins/stockMixin';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'stock-list',
|
name: 'stock-list',
|
||||||
components: { TrainImage },
|
components: { TrainImage, StockThumbnails },
|
||||||
|
|
||||||
mixins: [warningsMixin, imageMixin, stockPreviewMixin],
|
mixins: [warningsMixin, imageMixin, stockMixin, stockPreviewMixin],
|
||||||
|
|
||||||
setup() {
|
setup() {
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
@@ -208,6 +188,10 @@ export default defineComponent({
|
|||||||
.join(';');
|
.join(';');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
stockIsEmpty() {
|
||||||
|
return this.store.stockList.length == 0;
|
||||||
|
},
|
||||||
|
|
||||||
chosenStockVehicle() {
|
chosenStockVehicle() {
|
||||||
return this.store.chosenStockListIndex == -1 ? undefined : this.store.stockList[this.store.chosenStockListIndex];
|
return this.store.chosenStockListIndex == -1 ? undefined : this.store.stockList[this.store.chosenStockListIndex];
|
||||||
},
|
},
|
||||||
@@ -218,6 +202,10 @@ export default defineComponent({
|
|||||||
return this.tooManyLocomotives || this.trainTooHeavy || this.trainTooLong || this.locoNotSuitable;
|
return this.tooManyLocomotives || this.trainTooHeavy || this.trainTooLong || this.locoNotSuitable;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
stockImageError(e: Event, stock: IStock): void {
|
||||||
|
(e.target as HTMLImageElement).src = `images/${stock.useType}-unknown.png`;
|
||||||
|
},
|
||||||
|
|
||||||
copyToClipboard() {
|
copyToClipboard() {
|
||||||
// if (this.stockHasWarnings()) {
|
// if (this.stockHasWarnings()) {
|
||||||
// alert('Jazda tym pociągiem jest niezgodna z regulaminem symulatora! Zmień parametry zestawienia!');
|
// alert('Jazda tym pociągiem jest niezgodna z regulaminem symulatora! Zmień parametry zestawienia!');
|
||||||
@@ -282,6 +270,8 @@ export default defineComponent({
|
|||||||
if (index == -1) return;
|
if (index == -1) return;
|
||||||
|
|
||||||
this.store.stockList = this.store.stockList.filter((stock, i) => i != index);
|
this.store.stockList = this.store.stockList.filter((stock, i) => i != index);
|
||||||
|
|
||||||
|
if (this.store.stockList.length < index + 1) this.store.chosenStockListIndex = -1;
|
||||||
},
|
},
|
||||||
|
|
||||||
moveUpStock(index: number) {
|
moveUpStock(index: number) {
|
||||||
@@ -333,9 +323,13 @@ export default defineComponent({
|
|||||||
// if (this.stockHasWarnings())
|
// if (this.stockHasWarnings())
|
||||||
// return alert('Jazda tym pociągiem jest niezgodna z regulaminem symulatora! Zmień parametry zestawienia!');
|
// return alert('Jazda tym pociągiem jest niezgodna z regulaminem symulatora! Zmień parametry zestawienia!');
|
||||||
|
|
||||||
|
const defaultName = `${this.store.chosenRealStockName || this.store.stockList[0].type} ${
|
||||||
|
this.store.totalMass
|
||||||
|
}t; ${this.store.totalLength}m; vmax ${this.store.maxStockSpeed}`;
|
||||||
|
|
||||||
const fileName = prompt(
|
const fileName = prompt(
|
||||||
'Nazwij plik, a następnie pobierz do folderu Presets (Dokumenty/TTSK/TrainDriver2):',
|
'Nazwij plik, a następnie pobierz do folderu Presets (Dokumenty/TTSK/TrainDriver2):',
|
||||||
`${this.store.chosenRealStockName || this.store.stockList[0].type}`
|
defaultName
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!fileName) return;
|
if (!fileName) return;
|
||||||
@@ -352,6 +346,29 @@ export default defineComponent({
|
|||||||
a.dispatchEvent(e);
|
a.dispatchEvent(e);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
uploadStock() {
|
||||||
|
const inputEl = this.$refs['conFile'] as HTMLInputElement;
|
||||||
|
const files = inputEl.files;
|
||||||
|
|
||||||
|
if (files?.length != 1) return;
|
||||||
|
if (!/\.con$/.test(files[0].name)) return;
|
||||||
|
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.readAsText(files[0]);
|
||||||
|
|
||||||
|
reader.onload = (res) => {
|
||||||
|
const stockString = res.target?.result;
|
||||||
|
|
||||||
|
if (!stockString || typeof stockString !== 'string') return;
|
||||||
|
|
||||||
|
this.loadStockFromString(stockString);
|
||||||
|
};
|
||||||
|
|
||||||
|
reader.onerror = (err) => console.log(err);
|
||||||
|
|
||||||
|
inputEl.value = '';
|
||||||
|
},
|
||||||
|
|
||||||
onDragStart(vehicleIndex: number) {
|
onDragStart(vehicleIndex: number) {
|
||||||
this.draggedVehicleID = vehicleIndex;
|
this.draggedVehicleID = vehicleIndex;
|
||||||
},
|
},
|
||||||
@@ -379,11 +396,7 @@ export default defineComponent({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import '../styles/global';
|
@import '../../styles/global';
|
||||||
|
|
||||||
.stock_warnings {
|
|
||||||
margin-top: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.warning {
|
.warning {
|
||||||
padding: 0.25em;
|
padding: 0.25em;
|
||||||
@@ -403,12 +416,13 @@ export default defineComponent({
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
|
gap: 0.5em;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|
||||||
margin: 1em 0;
|
padding: 0.5em;
|
||||||
border: 1px solid white;
|
margin-bottom: 1em;
|
||||||
|
|
||||||
padding: 0 0.3em;
|
background-color: #353a57;
|
||||||
|
|
||||||
&[data-disabled='true'] {
|
&[data-disabled='true'] {
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
@@ -430,28 +444,26 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
margin: 0.25em;
|
|
||||||
padding: 0.25em;
|
|
||||||
|
|
||||||
&:focus-visible {
|
|
||||||
outline: 1px solid white;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
img {
|
||||||
vertical-align: text-bottom;
|
|
||||||
margin-right: 0.25em;
|
margin-right: 0.25em;
|
||||||
|
|
||||||
width: 1.1em;
|
|
||||||
height: 1.1em;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.stock_clipboard-text {
|
.stock_actions {
|
||||||
font-weight: bold;
|
display: grid;
|
||||||
|
gap: 0.5em;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
|
||||||
& > .btn {
|
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
|
||||||
margin: 0 0.5em 0.5em 0;
|
|
||||||
|
label.file-label {
|
||||||
|
text-align: center;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
input {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -466,8 +478,7 @@ ul {
|
|||||||
|
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
|
||||||
height: 70vh;
|
height: 500px;
|
||||||
margin-top: 1em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ul > li {
|
ul > li {
|
||||||
@@ -487,7 +498,8 @@ ul > li {
|
|||||||
|
|
||||||
&.list-empty {
|
&.list-empty {
|
||||||
background-color: $secondaryColor;
|
background-color: $secondaryColor;
|
||||||
padding: 0.5em;
|
border-radius: 0.5em;
|
||||||
|
padding: 0.75em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -509,6 +521,10 @@ li > .stock-info {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.stock_warnings {
|
||||||
|
margin: 0.5em 0;
|
||||||
|
}
|
||||||
|
|
||||||
.stock-info {
|
.stock-info {
|
||||||
&__no,
|
&__no,
|
||||||
&__type {
|
&__type {
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
<template>
|
||||||
|
<div class="stock_thumbnails" ref="thumbnailsRef">
|
||||||
|
<div
|
||||||
|
v-for="(stock, stockIndex) in store.stockList"
|
||||||
|
:data-selected="store.chosenStockListIndex == stockIndex"
|
||||||
|
draggable="true"
|
||||||
|
@dragstart="onDragStart(stockIndex)"
|
||||||
|
@drop="onDrop($event, stockIndex)"
|
||||||
|
@dragover="allowDrop"
|
||||||
|
>
|
||||||
|
<span @click="onListItemClick(stockIndex)" :key="stock.id">
|
||||||
|
<b>
|
||||||
|
{{ stock.type }}
|
||||||
|
</b>
|
||||||
|
|
||||||
|
<span>
|
||||||
|
<img
|
||||||
|
draggable="false"
|
||||||
|
:src="`https://rj.td2.info.pl/dist/img/thumbnails/${stock.type}.png`"
|
||||||
|
:alt="stock.type"
|
||||||
|
:title="stock.type"
|
||||||
|
@error="stockImageError($event, stock)"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { Ref, computed, nextTick, ref, watch } from 'vue';
|
||||||
|
import { useStore } from '../../store';
|
||||||
|
import { IStock } from '../../types';
|
||||||
|
|
||||||
|
const store = useStore();
|
||||||
|
const emit = defineEmits(['listItemClick', 'stockImageError']);
|
||||||
|
|
||||||
|
const thumbnailsRef = ref() as Ref<HTMLElement>;
|
||||||
|
const draggedIndex = ref(-1);
|
||||||
|
|
||||||
|
const onListItemClick = (index: number) => {
|
||||||
|
emit('listItemClick', index);
|
||||||
|
};
|
||||||
|
|
||||||
|
const stockImageError = (e: Event, stock: IStock) => {
|
||||||
|
emit('stockImageError', e, stock);
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
computed(() => store.chosenStockListIndex),
|
||||||
|
(index) => {
|
||||||
|
if (index < 0) return;
|
||||||
|
|
||||||
|
nextTick(() => {
|
||||||
|
(thumbnailsRef.value as HTMLElement)
|
||||||
|
.querySelector(`div:nth-child(${index + 1})`)
|
||||||
|
?.scrollIntoView({ block: 'nearest', inline: 'start', behavior: 'smooth' });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Dragging images
|
||||||
|
const onDragStart = (vehicleIndex: number) => {
|
||||||
|
draggedIndex.value = vehicleIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onDrop = (e: DragEvent, vehicleIndex: number) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
let targetEl = thumbnailsRef.value.querySelector(`div:nth-child(${vehicleIndex + 1})`);
|
||||||
|
|
||||||
|
if (!targetEl && draggedIndex.value != -1) return;
|
||||||
|
|
||||||
|
const tempVehicle = store.stockList[vehicleIndex];
|
||||||
|
store.stockList[vehicleIndex] = store.stockList[draggedIndex.value];
|
||||||
|
store.stockList[draggedIndex.value] = tempVehicle;
|
||||||
|
|
||||||
|
store.chosenStockListIndex = vehicleIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
const allowDrop = (e: DragEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.stock_thumbnails {
|
||||||
|
display: flex;
|
||||||
|
margin: 1em 0;
|
||||||
|
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
background-color: #353a57;
|
||||||
|
|
||||||
|
> div {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
cursor: pointer;
|
||||||
|
min-height: 100px;
|
||||||
|
|
||||||
|
&[data-selected='true'] {
|
||||||
|
background-color: rebeccapurple;
|
||||||
|
}
|
||||||
|
|
||||||
|
> span {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5em;
|
||||||
|
padding: 0.5em 0;
|
||||||
|
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
font-size: 0.85em;
|
||||||
|
user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-height: 60px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
{
|
||||||
|
"regionNumbers": {
|
||||||
|
"Warszawa": 1,
|
||||||
|
"Lublin": 2,
|
||||||
|
"Kraków": 3,
|
||||||
|
"Sosnowiec": 4,
|
||||||
|
"Gdańsk": 5,
|
||||||
|
"Wrocław": 6,
|
||||||
|
"Poznań": 7,
|
||||||
|
"Szczecin": 8,
|
||||||
|
"Rezerwa": 9
|
||||||
|
},
|
||||||
|
"sameRegions": {
|
||||||
|
"Losowy": [
|
||||||
|
10, 11, 19, 91, 93, 97, 99, 20, 22, 29, 30, 33, 39, 40, 44, 49, 94, 50, 55, 59, 90, 95, 96, 66, 60, 69, 77, 70,
|
||||||
|
79, 88, 80, 89, 92, 98
|
||||||
|
],
|
||||||
|
"Warszawa": [10, 11, 19, 91, 93, 97, 99],
|
||||||
|
"Lublin": [20, 22, 29],
|
||||||
|
"Kraków": [30, 33, 39],
|
||||||
|
"Sosnowiec": [40, 44, 49, 94],
|
||||||
|
"Gdańsk": [50, 55, 59, 90, 95, 96],
|
||||||
|
"Wrocław": [66, 60, 69],
|
||||||
|
"Poznań": [77, 70, 79],
|
||||||
|
"Szczecin": [88, 80],
|
||||||
|
"Rezerwa": [89, 92, 98]
|
||||||
|
},
|
||||||
|
"categories": {
|
||||||
|
"ekspres krajowy (EI)": "2:00-99:2",
|
||||||
|
"międzywojewódzki pośpieszny (MP)": "2:050-169:3",
|
||||||
|
"wojewódzki pośpieszny (RP)": "2:050-169:3",
|
||||||
|
"wojewódzki osobowy (RO)": "2:200-999:3",
|
||||||
|
"próżny \"służbowy\" (PW)": "2:6;3:0-899:3",
|
||||||
|
"towarowy do przewozów masowych (TM)": "2:4;3:0-899:3",
|
||||||
|
"towarowy do obsługi stacji (TK)": "2:3;3:0-899:3",
|
||||||
|
"lokomotywa luzem (LT)": "2:5;3:0-899:3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
{
|
||||||
|
"EU07": {
|
||||||
|
"passenger": {
|
||||||
|
"650": 125
|
||||||
|
},
|
||||||
|
"cargo": {
|
||||||
|
"2000": 70
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"EP07": {
|
||||||
|
"passenger": {
|
||||||
|
"650": 125
|
||||||
|
},
|
||||||
|
"cargo": null
|
||||||
|
},
|
||||||
|
"EP08": {
|
||||||
|
"passenger": {
|
||||||
|
"650": 140
|
||||||
|
},
|
||||||
|
"cargo": null
|
||||||
|
},
|
||||||
|
"ET41": {
|
||||||
|
"passenger": {
|
||||||
|
"700": 125
|
||||||
|
},
|
||||||
|
"cargo": {
|
||||||
|
"4000": 70
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"SM42": {
|
||||||
|
"passenger": {
|
||||||
|
"95": 90,
|
||||||
|
"200": 80,
|
||||||
|
"300": 70,
|
||||||
|
"450": 60,
|
||||||
|
"750": 50,
|
||||||
|
"1130": 40,
|
||||||
|
"1720": 30,
|
||||||
|
"2400": 20
|
||||||
|
},
|
||||||
|
"cargo": {
|
||||||
|
"95": 90,
|
||||||
|
"200": 80,
|
||||||
|
"300": 70,
|
||||||
|
"450": 60,
|
||||||
|
"750": 50,
|
||||||
|
"1130": 40,
|
||||||
|
"1720": 30,
|
||||||
|
"2400": 20
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+1
-5
@@ -7,11 +7,7 @@ import App from './App.vue';
|
|||||||
const pinia = createPinia();
|
const pinia = createPinia();
|
||||||
|
|
||||||
const updateSW = registerSW({
|
const updateSW = registerSW({
|
||||||
onOfflineReady() {},
|
immediate: true,
|
||||||
|
|
||||||
onNeedRefresh() {
|
|
||||||
console.log('Need refresh!');
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
createApp(App).use(pinia).mount('#app');
|
createApp(App).use(pinia).mount('#app');
|
||||||
|
|||||||
+55
-13
@@ -15,7 +15,7 @@ export default defineComponent({
|
|||||||
return `${Math.random().toString(36).slice(5)}`;
|
return `${Math.random().toString(36).slice(5)}`;
|
||||||
},
|
},
|
||||||
|
|
||||||
getStockObject(vehicle: Vehicle, cargo?: ICargo, count = 1): IStock {
|
getStockObject(vehicle: Vehicle, cargo?: ICargo | null, count = 1): IStock {
|
||||||
const isLoco = isLocomotive(vehicle);
|
const isLoco = isLocomotive(vehicle);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -33,13 +33,22 @@ export default defineComponent({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
addVehicle(vehicle: Vehicle | null, cargo?: ICargo | null) {
|
||||||
|
if (!vehicle) return;
|
||||||
|
|
||||||
|
const stock = this.getStockObject(vehicle, cargo);
|
||||||
|
|
||||||
|
if (stock.isLoco && !this.store.stockList[0]?.isLoco) this.store.stockList.unshift(stock);
|
||||||
|
else this.store.stockList.push(stock);
|
||||||
|
},
|
||||||
|
|
||||||
addLocomotive(loco: ILocomotive) {
|
addLocomotive(loco: ILocomotive) {
|
||||||
const previousStock =
|
// const previousStock =
|
||||||
this.store.stockList.length > 0 ? this.store.stockList[this.store.stockList.length - 1] : null;
|
// this.store.stockList.length > 0 ? this.store.stockList[this.store.stockList.length - 1] : null;
|
||||||
if (previousStock && previousStock.type == loco.type) {
|
// if (previousStock && previousStock.type == loco.type) {
|
||||||
this.store.stockList[this.store.stockList.length - 1].count++;
|
// this.store.stockList[this.store.stockList.length - 1].count++;
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
const stockObj = this.getStockObject(loco);
|
const stockObj = this.getStockObject(loco);
|
||||||
|
|
||||||
@@ -48,18 +57,51 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
addCarWagon(car: ICarWagon, cargo?: ICargo) {
|
addCarWagon(car: ICarWagon, cargo?: ICargo) {
|
||||||
const previousStock =
|
// const previousStock =
|
||||||
this.store.stockList.length > 0 ? this.store.stockList[this.store.stockList.length - 1] : null;
|
// this.store.stockList.length > 0 ? this.store.stockList[this.store.stockList.length - 1] : null;
|
||||||
|
|
||||||
if (previousStock && previousStock.type == car.type && previousStock.cargo?.id == cargo?.id) {
|
// if (previousStock && previousStock.type == car.type && previousStock.cargo?.id == cargo?.id) {
|
||||||
this.store.stockList[this.store.stockList.length - 1].count++;
|
// this.store.stockList[this.store.stockList.length - 1].count++;
|
||||||
|
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
const stockObj = this.getStockObject(car, cargo);
|
const stockObj = this.getStockObject(car, cargo);
|
||||||
|
|
||||||
this.store.stockList.push(stockObj);
|
this.store.stockList.push(stockObj);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
loadStockFromString(stockString: string) {
|
||||||
|
const stockArray = stockString.trim().split(';');
|
||||||
|
|
||||||
|
this.store.stockList.length = 0;
|
||||||
|
this.store.chosenVehicle = null;
|
||||||
|
this.store.chosenCar = null;
|
||||||
|
this.store.chosenCargo = null;
|
||||||
|
this.store.chosenLoco = null;
|
||||||
|
this.store.chosenStockListIndex = -1;
|
||||||
|
|
||||||
|
this.store.swapVehicles = false;
|
||||||
|
|
||||||
|
stockArray.forEach((type) => {
|
||||||
|
let vehicle: Vehicle | null = null;
|
||||||
|
let vehicleCargo: ICargo | null = null;
|
||||||
|
|
||||||
|
if (/^(EU|EP|ET|SM|EN|2EN|SN)/.test(type)) {
|
||||||
|
const [locoType, coldStart] = type.split(',');
|
||||||
|
vehicle = this.store.locoDataList.find((loco) => loco.type == locoType) || null;
|
||||||
|
} else {
|
||||||
|
const [carType, cargo] = type.split(':');
|
||||||
|
vehicle = this.store.carDataList.find((car) => car.type == carType) || null;
|
||||||
|
|
||||||
|
if (cargo) vehicleCargo = vehicle?.cargoList.find((c) => c.id == cargo) || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vehicle) console.log('Brak pojazdu:', type);
|
||||||
|
|
||||||
|
this.addVehicle(vehicle, vehicleCargo);
|
||||||
|
});
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -18,32 +18,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
trainTooHeavy() {
|
trainTooHeavy() {
|
||||||
const totalMass = this.store.totalMass;
|
return this.store.acceptableMass && this.store.totalMass > this.store.acceptableMass;
|
||||||
const isTrainPassenger = this.store.isTrainPassenger;
|
|
||||||
const stockList = this.store.stockList;
|
|
||||||
|
|
||||||
if (stockList.length == 0 || !stockList[0].isLoco) return false;
|
|
||||||
|
|
||||||
const activeLocomotiveType = stockList[0].type;
|
|
||||||
|
|
||||||
// Spalinowy SM
|
|
||||||
if (/^SM/.test(activeLocomotiveType) && totalMass > 2400) return true;
|
|
||||||
|
|
||||||
// Elektryczne EU07 / EP07 / EP08 / ET41
|
|
||||||
|
|
||||||
// Pasażerski elektr.
|
|
||||||
if (isTrainPassenger) {
|
|
||||||
if (/^(EU|EP)/.test(activeLocomotiveType) && totalMass > 650) return true;
|
|
||||||
if (/^ET/.test(activeLocomotiveType) && totalMass > 700) return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Towarowy / inny elektr.
|
|
||||||
if (/^EU/.test(activeLocomotiveType) && totalMass > 2000) return true;
|
|
||||||
if (/^ET/.test(activeLocomotiveType) && totalMass > 4000) return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
locoNotSuitable() {
|
locoNotSuitable() {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { IStore } from './types';
|
import { IStore } from './types';
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import {
|
import {
|
||||||
|
acceptableMass,
|
||||||
carDataList,
|
carDataList,
|
||||||
chosenRealStock,
|
chosenRealStock,
|
||||||
isTrainPassenger,
|
isTrainPassenger,
|
||||||
@@ -53,6 +54,7 @@ export const useStore = defineStore({
|
|||||||
maxStockSpeed: (state) => maxStockSpeed(state),
|
maxStockSpeed: (state) => maxStockSpeed(state),
|
||||||
isTrainPassenger: (state) => isTrainPassenger(state),
|
isTrainPassenger: (state) => isTrainPassenger(state),
|
||||||
chosenRealStock: (state) => chosenRealStock(state),
|
chosenRealStock: (state) => chosenRealStock(state),
|
||||||
|
acceptableMass: (state) => acceptableMass(state),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
+14
-14
@@ -3,14 +3,14 @@
|
|||||||
$breakpointMd: 960px;
|
$breakpointMd: 960px;
|
||||||
$breakpointSm: 550px;
|
$breakpointSm: 550px;
|
||||||
|
|
||||||
$bgColor: #2c3149;
|
$bgColor: #2b3552;
|
||||||
$textColor: #fff;
|
$textColor: #fff;
|
||||||
$secondaryColor: #222;
|
$secondaryColor: #222;
|
||||||
$accentColor: #e4c428;
|
$accentColor: #e4c428;
|
||||||
|
|
||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
width: 0.5rem;
|
width: 7px;
|
||||||
height: 0.5rem;
|
height: 7px;
|
||||||
|
|
||||||
&-track {
|
&-track {
|
||||||
background: #222;
|
background: #222;
|
||||||
@@ -21,6 +21,10 @@ $accentColor: #e4c428;
|
|||||||
border-radius: 1rem;
|
border-radius: 1rem;
|
||||||
background: #777;
|
background: #777;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&-corner {
|
||||||
|
background: #222;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
body,
|
body,
|
||||||
@@ -31,7 +35,6 @@ html {
|
|||||||
font-family: 'Lato', sans-serif;
|
font-family: 'Lato', sans-serif;
|
||||||
|
|
||||||
background-color: $bgColor;
|
background-color: $bgColor;
|
||||||
width: 100vw;
|
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,14 +84,20 @@ button {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
button.btn {
|
.btn {
|
||||||
padding: 0.4em 0.75em;
|
padding: 0.4em 0.75em;
|
||||||
|
|
||||||
outline: none;
|
outline: none;
|
||||||
background-color: #222;
|
background-color: #222;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-weight: bold;
|
||||||
|
|
||||||
transition: all 250ms;
|
transition: all 250ms;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: $accentColor;
|
||||||
|
}
|
||||||
|
|
||||||
&.btn--outline {
|
&.btn--outline {
|
||||||
background: none;
|
background: none;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
@@ -120,15 +129,6 @@ button.btn {
|
|||||||
outline: 1px solid white;
|
outline: 1px solid white;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&--choice {
|
|
||||||
padding: 0.25em 0.3em;
|
|
||||||
background-color: #222;
|
|
||||||
|
|
||||||
&:focus-visible {
|
|
||||||
outline: 1px solid white;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
select,
|
select,
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
@import './global.scss';
|
||||||
|
|
||||||
|
.tab {
|
||||||
|
height: 100%;
|
||||||
|
margin-top: 1px;
|
||||||
|
|
||||||
|
&_header {
|
||||||
|
padding: 0.5em 1em;
|
||||||
|
|
||||||
|
background-color: $secondaryColor;
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin: 0;
|
||||||
|
color: white;
|
||||||
|
font-size: 1.35em;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&_content {
|
||||||
|
margin-top: 1em;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&_attributes {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 1em;
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
max-width: 250px;
|
||||||
|
margin-top: 0.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&_actions {
|
||||||
|
display: grid;
|
||||||
|
gap: 0.5em;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
|
||||||
|
button {
|
||||||
|
padding: 0.5em;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-disabled] button {
|
||||||
|
opacity: 0.75;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
height: 3px;
|
||||||
|
background-color: white;
|
||||||
|
outline: none;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 470px) {
|
||||||
|
.tab_attributes {
|
||||||
|
label {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
max-width: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+11
-2
@@ -27,7 +27,7 @@ export interface IStore {
|
|||||||
isRandomizerCardOpen: boolean;
|
isRandomizerCardOpen: boolean;
|
||||||
isRealStockListCardOpen: boolean;
|
isRealStockListCardOpen: boolean;
|
||||||
|
|
||||||
stockSectionMode: 'stock-list' | 'stock-generator';
|
stockSectionMode: 'stock-list' | 'stock-generator' | 'number-generator';
|
||||||
stockData?: IStockData;
|
stockData?: IStockData;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,7 +49,12 @@ export interface IStockData {
|
|||||||
};
|
};
|
||||||
|
|
||||||
info: {
|
info: {
|
||||||
[key in TStockInfoKey]: any[];
|
'car-cargo': [string, string, boolean, boolean, string][];
|
||||||
|
'car-passenger': [string, string, boolean, boolean, string][];
|
||||||
|
'loco-e': [string, string, string, string, boolean][];
|
||||||
|
'loco-s': [string, string, string, string, boolean][];
|
||||||
|
'loco-szt': [string, string, string, string, boolean][];
|
||||||
|
'loco-ezt': [string, string, string, string, boolean][];
|
||||||
};
|
};
|
||||||
|
|
||||||
props: IStockProps[];
|
props: IStockProps[];
|
||||||
@@ -108,3 +113,7 @@ export interface IReadyStockList {
|
|||||||
[key: string]: { stockString: string; type: string; number: string; name: string };
|
[key: string]: { stockString: string; type: string; number: string; name: string };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import speedLimitTable from '../constants/speedLimits.json';
|
||||||
|
export type LocoType = keyof typeof speedLimitTable;
|
||||||
|
|
||||||
|
export const calculateSpeedLimit = (locoType: LocoType, stockMass: number, isTrainPassenger: boolean) => {
|
||||||
|
const speedTable = speedLimitTable[locoType][isTrainPassenger ? 'passenger' : 'cargo'];
|
||||||
|
|
||||||
|
if (!speedTable) return undefined;
|
||||||
|
|
||||||
|
let speedLimit = 0;
|
||||||
|
for (let mass in speedTable) if (stockMass > Number(mass)) speedLimit = (speedTable as any)[mass];
|
||||||
|
|
||||||
|
return speedLimit;
|
||||||
|
};
|
||||||
|
|
||||||
+75
-239
@@ -1,35 +1,6 @@
|
|||||||
import { EVehicleUseType } from '../enums/EVehicleUseType';
|
import { EVehicleUseType } from '../enums/EVehicleUseType';
|
||||||
import { ICarWagon, ILocomotive, IStore, TStockInfoKey } from '../types';
|
import { ICarWagon, ILocomotive, IStore, TStockInfoKey } from '../types';
|
||||||
|
import { LocoType, calculateSpeedLimit } from './speedLimitUtils';
|
||||||
// rodzaj: [tMaxPas, vMaxPas, tMaxTow, vMaxTow] | SM42: [tMax, vMax, ...]
|
|
||||||
const maxAllowedSpeedTable = {
|
|
||||||
EU07: [
|
|
||||||
[650, 125],
|
|
||||||
[2000, 70],
|
|
||||||
],
|
|
||||||
EP07: [
|
|
||||||
[650, 125],
|
|
||||||
[0, 0],
|
|
||||||
],
|
|
||||||
EP08: [
|
|
||||||
[650, 140],
|
|
||||||
[0, 0],
|
|
||||||
],
|
|
||||||
ET41: [
|
|
||||||
[700, 125],
|
|
||||||
[4000, 70],
|
|
||||||
],
|
|
||||||
SM42: [
|
|
||||||
[95, 90],
|
|
||||||
[200, 80],
|
|
||||||
[300, 70],
|
|
||||||
[450, 60],
|
|
||||||
[750, 50],
|
|
||||||
[1130, 40],
|
|
||||||
[1720, 30],
|
|
||||||
[2400, 20],
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
export function isLocomotive(vehicle: ILocomotive | ICarWagon): vehicle is ILocomotive {
|
export function isLocomotive(vehicle: ILocomotive | ICarWagon): vehicle is ILocomotive {
|
||||||
return (vehicle as ILocomotive).power !== undefined;
|
return (vehicle as ILocomotive).power !== undefined;
|
||||||
@@ -40,84 +11,28 @@ export function locoDataList(state: IStore) {
|
|||||||
|
|
||||||
const stockData = state.stockData;
|
const stockData = state.stockData;
|
||||||
|
|
||||||
return Object.keys(stockData.info).reduce((acc, vehicleTypeKey) => {
|
return Object.keys(stockData.info).reduce((acc, vehiclePower) => {
|
||||||
if (!vehicleTypeKey.startsWith('loco')) return acc;
|
if (!vehiclePower.startsWith('loco')) return acc;
|
||||||
|
|
||||||
const locoVehiclesData = stockData.info[vehicleTypeKey as TStockInfoKey];
|
const locoVehiclesData = stockData.info[vehiclePower as 'loco-e' | 'loco-s' | 'loco-ezt' | 'loco-szt'];
|
||||||
|
|
||||||
locoVehiclesData.forEach((loco) => {
|
locoVehiclesData.forEach((loco) => {
|
||||||
if (state.showSupporter && !loco[4]) return;
|
if (state.showSupporter && !loco[4]) return;
|
||||||
|
|
||||||
const locoType = loco[0] as string;
|
const [type, constructionType, cabinType, maxSpeed, supportersOnly] = loco;
|
||||||
|
const locoProps = stockData.props.find((prop) => constructionType == prop.type);
|
||||||
let length = 0,
|
|
||||||
mass = 0;
|
|
||||||
|
|
||||||
// Elektrowozy
|
|
||||||
if (vehicleTypeKey.startsWith('loco-e')) {
|
|
||||||
// 32m dla ET41, reszta 16
|
|
||||||
length = locoType.startsWith('ET') ? 32 : 16;
|
|
||||||
|
|
||||||
// 80t dla wszystkich EU06, EP08
|
|
||||||
mass = 80;
|
|
||||||
|
|
||||||
// 83t dla: EU07 o nr większych niż 300 & dla wszystkich EP07 oprócz nr 135,242,1002,1048
|
|
||||||
const locoNumber = Number(locoType.split('-')[1]);
|
|
||||||
|
|
||||||
if (
|
|
||||||
(locoType.startsWith('EU') && locoNumber > 300) ||
|
|
||||||
(locoType.startsWith('EP') && ![242, 135, 1002, 1048].includes(locoNumber))
|
|
||||||
) {
|
|
||||||
mass = 83;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (locoType.startsWith('ET')) {
|
|
||||||
mass = 167;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Spalinowozy
|
|
||||||
if (vehicleTypeKey.startsWith('loco-s')) {
|
|
||||||
length = 14;
|
|
||||||
mass = 74;
|
|
||||||
}
|
|
||||||
|
|
||||||
// EZT
|
|
||||||
if (vehicleTypeKey.startsWith('loco-ezt')) {
|
|
||||||
// EN57
|
|
||||||
length = 65;
|
|
||||||
mass = 126;
|
|
||||||
|
|
||||||
// EN71
|
|
||||||
if (locoType.startsWith('EN71')) {
|
|
||||||
length = 86;
|
|
||||||
mass = 182;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2xEN57
|
|
||||||
if (locoType.startsWith('2EN57')) {
|
|
||||||
length = 130;
|
|
||||||
mass = 253;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SZT
|
|
||||||
if (vehicleTypeKey.startsWith('loco-szt')) {
|
|
||||||
length = 14;
|
|
||||||
mass = 23;
|
|
||||||
}
|
|
||||||
|
|
||||||
acc.push({
|
acc.push({
|
||||||
power: vehicleTypeKey,
|
power: vehiclePower,
|
||||||
type: loco[0] as string,
|
type,
|
||||||
constructionType: loco[1] as string,
|
constructionType,
|
||||||
cabinType: loco[2] as string,
|
cabinType,
|
||||||
maxSpeed: Number(loco[3] as string),
|
maxSpeed: Number(maxSpeed),
|
||||||
supportersOnly: loco[4] as boolean,
|
supportersOnly,
|
||||||
imageSrc: loco[5] as string,
|
imageSrc: '',
|
||||||
|
|
||||||
length,
|
length: locoProps?.length && type.startsWith('2EN') ? locoProps.length * 2 : locoProps?.length || 0,
|
||||||
mass,
|
mass: locoProps?.mass && type.startsWith('2EN') ? 253 : locoProps?.mass || 0,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -130,10 +45,10 @@ export function carDataList(state: IStore) {
|
|||||||
|
|
||||||
const stockData = state.stockData;
|
const stockData = state.stockData;
|
||||||
|
|
||||||
return Object.keys(stockData.info).reduce((acc, vehicleTypeKey) => {
|
return Object.keys(stockData.info).reduce((acc, vehicleUseType) => {
|
||||||
if (!vehicleTypeKey.startsWith('car')) return acc;
|
if (!vehicleUseType.startsWith('car')) return acc;
|
||||||
|
|
||||||
const carVehiclesData = stockData.info[vehicleTypeKey as TStockInfoKey];
|
const carVehiclesData = stockData.info[vehicleUseType as 'car-passenger' | 'car-cargo'];
|
||||||
|
|
||||||
carVehiclesData.forEach((car) => {
|
carVehiclesData.forEach((car) => {
|
||||||
if (state.showSupporter && !car[3]) return;
|
if (state.showSupporter && !car[3]) return;
|
||||||
@@ -141,19 +56,21 @@ export function carDataList(state: IStore) {
|
|||||||
const carPropsData = stockData.props.find((v) => car[0].toString().startsWith(v.type));
|
const carPropsData = stockData.props.find((v) => car[0].toString().startsWith(v.type));
|
||||||
|
|
||||||
acc.push({
|
acc.push({
|
||||||
useType: vehicleTypeKey as 'car-passenger' | 'car-cargo',
|
useType: vehicleUseType as 'car-passenger' | 'car-cargo',
|
||||||
type: car[0] as string,
|
type: car[0],
|
||||||
constructionType: car[1] as string,
|
constructionType: car[1],
|
||||||
loadable: car[2] as boolean,
|
loadable: car[2],
|
||||||
supportersOnly: car[3] as boolean,
|
supportersOnly: car[3],
|
||||||
maxSpeed: Number(car[4] as string),
|
maxSpeed: Number(car[4]),
|
||||||
imageSrc: car[5] as string,
|
imageSrc: '',
|
||||||
cargoList: carPropsData?.cargo.split(';').filter((s) => s.length > 0)
|
cargoList:
|
||||||
? carPropsData.cargo.split(';').map((cargo) => ({
|
!carPropsData || carPropsData.cargo === null
|
||||||
id: cargo.split(':')[0],
|
? []
|
||||||
totalMass: Number(cargo.split(':')[1]),
|
: carPropsData.cargo.split(';').map((cargo) => ({
|
||||||
}))
|
id: cargo.split(':')[0],
|
||||||
: [],
|
totalMass: Number(cargo.split(':')[1]),
|
||||||
|
})),
|
||||||
|
|
||||||
mass: carPropsData?.mass || 0,
|
mass: carPropsData?.mass || 0,
|
||||||
length: carPropsData?.length || 0,
|
length: carPropsData?.length || 0,
|
||||||
});
|
});
|
||||||
@@ -164,7 +81,7 @@ export function carDataList(state: IStore) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function totalMass(state: IStore) {
|
export function totalMass(state: IStore) {
|
||||||
return state.stockList.reduce(
|
return ~~state.stockList.reduce(
|
||||||
(acc, stock) => acc + (stock.cargo ? stock.cargo.totalMass : stock.mass) * stock.count,
|
(acc, stock) => acc + (stock.cargo ? stock.cargo.totalMass : stock.mass) * stock.count,
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
@@ -175,7 +92,47 @@ export function totalLength(state: IStore) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function maxStockSpeed(state: IStore) {
|
export function maxStockSpeed(state: IStore) {
|
||||||
return state.stockList.reduce((acc, stock) => (stock.maxSpeed < acc || acc == 0 ? stock.maxSpeed : acc), 0);
|
const stockSpeedLimit = state.stockList.reduce(
|
||||||
|
(acc, stock) => (stock.maxSpeed < acc || acc == 0 ? stock.maxSpeed : acc),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
const headingLoco = state.stockList[0]?.isLoco ? state.stockList[0] : undefined;
|
||||||
|
|
||||||
|
if (!headingLoco) return stockSpeedLimit;
|
||||||
|
|
||||||
|
const locoType = headingLoco.type.split('-')[0];
|
||||||
|
|
||||||
|
if (/^(EN|2EN|SN)/.test(locoType)) return stockSpeedLimit;
|
||||||
|
|
||||||
|
const stockMass = totalMass(state);
|
||||||
|
|
||||||
|
const speedLimitByMass = calculateSpeedLimit(locoType as LocoType, stockMass, isTrainPassenger(state));
|
||||||
|
|
||||||
|
return speedLimitByMass ? Math.min(stockSpeedLimit, speedLimitByMass) : stockSpeedLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function acceptableMass(state: IStore) {
|
||||||
|
if (state.stockList.length == 0 || !state.stockList[0].isLoco) return 0;
|
||||||
|
const activeLocomotiveType = state.stockList[0].type;
|
||||||
|
|
||||||
|
if (/^SM/.test(activeLocomotiveType)) return 2400;
|
||||||
|
|
||||||
|
// Elektryczne EU07 / EP07 / EP08 / ET41
|
||||||
|
|
||||||
|
// Pasażerski elektr.
|
||||||
|
if (isTrainPassenger(state)) {
|
||||||
|
if (/^(EU|EP)/.test(activeLocomotiveType)) return 650;
|
||||||
|
if (/^ET/.test(activeLocomotiveType)) return 700;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Towarowy / inny elektr.
|
||||||
|
if (/^EU/.test(activeLocomotiveType)) return 2000;
|
||||||
|
if (/^ET/.test(activeLocomotiveType)) return 4000;
|
||||||
|
if (/^EP/.test(activeLocomotiveType)) return 650;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isTrainPassenger(state: IStore) {
|
export function isTrainPassenger(state: IStore) {
|
||||||
@@ -206,124 +163,3 @@ export function chosenRealStock(state: IStore) {
|
|||||||
return realStockObj;
|
return realStockObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
// export function maxAllowedSpeed(state: IStore) {
|
|
||||||
// const headLocoType = state.stockList[0]?.isLoco ? state.stockList[0].type : undefined;
|
|
||||||
|
|
||||||
// if (!headLocoType) return 0;
|
|
||||||
|
|
||||||
// const isPassenger = isTrainPassenger(state);
|
|
||||||
// const stockMass = totalMass(state);
|
|
||||||
|
|
||||||
// // const maxSpeed = maxAllowedSpeedTable[headLocoType];
|
|
||||||
|
|
||||||
// // if()
|
|
||||||
// }
|
|
||||||
|
|
||||||
// export function maxAllowedSpeed(state: IStore) {
|
|
||||||
// if (state.stockList.length < 1) return -1;
|
|
||||||
// if (!state.stockList[0].isLoco) return -1;
|
|
||||||
|
|
||||||
// const headingLoco = state.stockList[0];
|
|
||||||
// const isPassenger = isTrainPassenger(state);
|
|
||||||
|
|
||||||
// if (headingLoco.type.startsWith('EU07')) {
|
|
||||||
// if (isPassenger && totalMass.value <= 650) return 125;
|
|
||||||
// if (!isPassenger && totalMass.value <= 2000) return 70;
|
|
||||||
|
|
||||||
// return -1;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (headingLoco.type.startsWith('EP07')) {
|
|
||||||
// if (isPassenger && totalMass.value <= 650) return 125;
|
|
||||||
// if (!isPassenger) return -1;
|
|
||||||
|
|
||||||
// return -1;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (headingLoco.type.startsWith('EP08')) {
|
|
||||||
// if (isPassenger && totalMass.value <= 650) return 140;
|
|
||||||
// if (!isPassenger) return -1;
|
|
||||||
|
|
||||||
// return -1;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (headingLoco.type.startsWith('ET41')) {
|
|
||||||
// if (isPassenger && totalMass.value <= 700) return 125;
|
|
||||||
// if (!isPassenger && totalMass.value <= 4000) return 70;
|
|
||||||
|
|
||||||
// return -1;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (headingLoco.type.startsWith('SM42')) {
|
|
||||||
// if (totalMass.value <= 95) return 90;
|
|
||||||
// if (totalMass.value <= 200) return 80;
|
|
||||||
// if (totalMass.value <= 300) return 70;
|
|
||||||
// if (totalMass.value <= 450) return 60;
|
|
||||||
// if (totalMass.value <= 750) return 50;
|
|
||||||
// if (totalMass.value <= 1130) return 40;
|
|
||||||
// if (totalMass.value <= 1720) return 30;
|
|
||||||
// if (totalMass.value <= 2400) return 20;
|
|
||||||
|
|
||||||
// return -1;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return Store.stockList.reduce((acc, stock) => (stock.maxSpeed < acc || acc == 0 ? stock.maxSpeed : acc), 0);
|
|
||||||
// });
|
|
||||||
|
|
||||||
// export const warnings = {
|
|
||||||
// trainTooLong: computed(() => {
|
|
||||||
// if (isTrainPassenger.value && totalLength.value > 350) return true;
|
|
||||||
// if (!isTrainPassenger.value && totalLength.value > 650) return true;
|
|
||||||
|
|
||||||
// return false;
|
|
||||||
// }),
|
|
||||||
|
|
||||||
// locoNotSuitable: computed(() => {
|
|
||||||
// if (
|
|
||||||
// !isTrainPassenger.value &&
|
|
||||||
// Store.stockList.length > 1 &&
|
|
||||||
// !Store.stockList.every((stock) => stock.isLoco) &&
|
|
||||||
// Store.stockList.find((stock) => stock.isLoco && stock.type.startsWith('EP'))
|
|
||||||
// )
|
|
||||||
// return true;
|
|
||||||
|
|
||||||
// return false;
|
|
||||||
// }),
|
|
||||||
|
|
||||||
// trainTooHeavy: computed(() => {
|
|
||||||
// if (Store.stockList.length == 0 || !Store.stockList[0].isLoco) return false;
|
|
||||||
|
|
||||||
// const headingLoco = Store.stockList[0];
|
|
||||||
|
|
||||||
// if (
|
|
||||||
// isTrainPassenger.value &&
|
|
||||||
// (headingLoco.type.startsWith('EU') || headingLoco.type.startsWith('EP')) &&
|
|
||||||
// totalMass.value > 650
|
|
||||||
// )
|
|
||||||
// return true;
|
|
||||||
// if (isTrainPassenger.value && headingLoco.type.startsWith('ET') && totalMass.value > 700) return true;
|
|
||||||
|
|
||||||
// if (!isTrainPassenger.value && headingLoco.type.startsWith('EU') && totalMass.value > 2000) return true;
|
|
||||||
// if (!isTrainPassenger.value && headingLoco.type.startsWith('ET') && totalMass.value > 4000) return true;
|
|
||||||
|
|
||||||
// if (headingLoco.type.startsWith('SM') && totalMass.value > 2400) return true;
|
|
||||||
|
|
||||||
// return false;
|
|
||||||
// }),
|
|
||||||
|
|
||||||
// tooManyLocos: computed(() => {
|
|
||||||
// if (
|
|
||||||
// Store.stockList.reduce((acc, stock) => {
|
|
||||||
// if (!stock.isLoco) return acc;
|
|
||||||
|
|
||||||
// acc += stock.count;
|
|
||||||
|
|
||||||
// return acc;
|
|
||||||
// }, 0) > 2
|
|
||||||
// )
|
|
||||||
// return true;
|
|
||||||
|
|
||||||
// return false;
|
|
||||||
// }),
|
|
||||||
// };
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user