Lokalne zapisywanie rozkazów

This commit is contained in:
2022-07-22 00:17:39 +02:00
parent 459c23df17
commit 667987bdb6
13 changed files with 450 additions and 77 deletions
+4
View File
@@ -0,0 +1,4 @@
<svg width="144" height="144" viewBox="0 0 144 144" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M76.3333 17.9839C76.3267 15.5906 74.3812 13.6578 71.988 13.6667C69.5948 13.6756 67.6601 15.6229 67.6667 18.0161L76.3333 17.9839ZM72.2408 105.15L97.1394 61.7232L47.1027 61.9097L72.2408 105.15ZM67.6667 18.0161L67.7997 66.1659L76.4663 66.1336L76.3333 17.9839L67.6667 18.0161Z" fill="white"/>
<path d="M14 83.2536V127H131V83.2536" stroke="white" stroke-width="11.2667" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 530 B

+3 -3
View File
@@ -33,11 +33,11 @@ export default defineComponent({
computed: {
chosenOrderComponent() {
switch (this.store.chosenOrderType) {
case 'OrderN':
case 'orderN':
return OrderNVue;
case 'OrderS':
case 'orderS':
return OrderSVue;
case 'OrderO':
case 'orderO':
return OrderOVue;
default:
return OrderNVue;
+118
View File
@@ -0,0 +1,118 @@
<template>
<section class="order-list">
<h3>Zapisane rozkazy pisemne ({{ localOrderCount }})</h3>
<ul>
<li v-for="order in sortedOrderList" @click="selectLocalOrder(order)">
<b>
{{ getOrderName(order.orderType) }} nr {{ order.orderBody['header']['orderNo'] }} dla pociągu nr
{{ order.orderBody['header']['trainNo'] }}
</b>
<br />
Dodano: {{ new Date(order.createdAt).toLocaleString('pl-PL') }}
</li>
</ul>
</section>
</template>
<script lang="ts">
import { defineComponent, reactive } from 'vue';
import { useStore } from '../store/store';
import { LocalStorageOrder } from '../types/orderTypes';
export default defineComponent({
name: 'OrderList',
data() {
return {
localOrderCount: 0,
localOrderList: [] as LocalStorageOrder[],
};
},
setup() {
return {
store: useStore(),
};
},
methods: {
getOrderName(orderType: string) {
return `Rozkaz "${orderType.split('order')[1]}"`;
},
selectLocalOrder(order: LocalStorageOrder) {
this.store.chosenOrderType = order.orderType;
const orderBody = JSON.parse(JSON.stringify(order.orderBody));
switch (order.orderType) {
case 'orderN':
// for (let key in this.store[order.orderType]) {
// (this.store[order.orderType] as any)[key] = orderBody[key];
// }
// this.store['orderN']['header'] = orderBody['header'];
// this.store['orderN']['row1'] = orderBody['row1'];
// this.store['orderN']['header'] = orderBody['header'];
// this.store['orderN']['header'] = orderBody['header'];
// this.store['orderN']['header'] = orderBody['header'];
break;
default:
break;
}
this.store[order.orderType] = reactive(JSON.parse(JSON.stringify(order.orderBody)));
},
},
computed: {
sortedOrderList() {
return this.localOrderList.sort((a, b) => a.createdAt - b.createdAt);
},
},
activated() {
const localStorage = window.localStorage;
const orderList = [];
this.localOrderCount = Number(localStorage.getItem('orderCount')) || 0;
for (let key in localStorage) {
if (!/^order-/g.test(key)) continue;
const orderObj: LocalStorageOrder = JSON.parse(localStorage[key]);
if (!orderObj) continue;
orderList.push(orderObj);
}
this.localOrderList = orderList;
},
});
</script>
<style lang="scss" scoped>
.order-list {
padding: 1em;
width: 500px;
}
ul {
overflow: auto;
height: 60vh;
}
h3 {
margin: 0;
margin-bottom: 1em;
text-align: center;
}
li {
text-align: left;
padding: 1em;
margin: 0.5em;
background-color: #222;
cursor: pointer;
}
</style>
+174
View File
@@ -0,0 +1,174 @@
<template>
<section class="order-message">
<h3>Wiadomość do wyświetlenia na czacie symulatora:</h3>
<div class="message_body" v-html="fullOrderMessage"></div>
<div class="message_actions">
<button class="g-button" @click="saveOrder"><img :src="saveIcon" alt="save icon" />Zapisz ten rozkaz</button>
<button class="g-button" @click="copyMessage">Kopiuj wiadomość rozkazu</button>
</div>
<transition name="monit-anim">
<div class="action_monit" v-if="actionMonit" v-html="actionMonit"></div>
</transition>
</section>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { useStore } from '../store/store';
import saveIcon from '../assets/icon-save.svg';
import orderStorageMixin from '../mixins/orderStorageMixin';
export default defineComponent({
name: 'OrderMessage',
mixins: [orderStorageMixin],
data() {
return {
saveIcon,
actionMonit: '',
monitTimeout: undefined as number | undefined,
};
},
setup() {
return {
store: useStore(),
};
},
computed: {
fullOrderMessage() {
return this.store.orderMessage + this.store.footerMessage;
},
},
methods: {
showActionMonit(text: string) {
if (this.monitTimeout) {
this.actionMonit = '';
clearTimeout(this.monitTimeout);
setTimeout(() => {
this.actionMonit = text;
this.monitTimeout = setTimeout(() => {
this.actionMonit = '';
}, 5000);
}, 300);
return;
}
this.actionMonit = text;
this.monitTimeout = setTimeout(() => {
this.actionMonit = '';
}, 5000);
},
copyMessage() {
if (!navigator.clipboard)
return this.showActionMonit(
'Ups! Twoja przeglądarka musi być dosyć przestarzała, ponieważ nie obsługuje zapisu do schowka! :/'
);
navigator.clipboard.writeText(this.fullOrderMessage);
this.showActionMonit(
'Skopiowano do <b class="text--accent">schowka</b>! Możesz teraz wkleić treść rozkazu na czacie symulatora!'
);
},
saveOrder() {
const savedOrderStatus = this.saveOrderToStorage();
switch (savedOrderStatus) {
case -1:
this.showActionMonit('<span class="text--warn">Wypełnij numer rozkazu, numer pociągu i datę zanim dodasz rozkaz!</span>');
break;
case 0:
this.showActionMonit('<span class="text--warn">Ostatni zapisany rozkaz jest identyczny z obecnym!</span>');
break;
case 1:
this.showActionMonit('Zapisano treść <b class="text--accent">rozkazu</b> w pamięci przeglądarki!');
break;
default:
break;
}
},
},
});
</script>
<style lang="scss" scoped>
.order-message {
padding: 1em;
width: 500px;
h3 {
margin: 0;
margin-bottom: 1em;
text-align: center;
}
button {
margin: 0 0.5em;
}
@media screen and (max-width: 550px) {
max-width: 100%;
}
}
.message_body {
height: 250px;
overflow: auto;
text-align: justify;
background-color: #fff;
border-radius: 0.5em;
color: black;
padding: 0.5em;
user-select: none;
-moz-user-select: none;
-webkit-user-select: none;
}
.message_actions {
display: flex;
align-items: center;
justify-content: center;
margin-top: 1em;
button img {
height: 2ch;
vertical-align: text-bottom;
margin-right: 0.5em;
}
}
.action_monit {
text-align: center;
padding: 1.5em;
font-size: 1.15em;
}
.monit-anim {
&-enter-active,
&-leave-active {
transition: all 100ms ease-in-out;
}
&-enter-from,
&-leave-to {
opacity: 0;
transform: translateY(-20px);
}
}
</style>
+1 -1
View File
@@ -312,7 +312,7 @@ export default defineComponent({
return {
store,
order: store.orderN,
order,
rowMethods,
};
},
+1 -1
View File
@@ -96,7 +96,7 @@ export default defineComponent({
return {
store,
order: store.orderO,
order,
rowMethods,
};
},
+1 -1
View File
@@ -215,7 +215,7 @@ export default defineComponent({
return {
store,
order: store.orderS,
order,
rowMethods,
};
},
+33 -7
View File
@@ -11,6 +11,11 @@
<div class="bar"></div>
</button>
<button class="option-save" @click="toggleOrderMode" :data-selected="store.orderMode == 'OrderList'">
<img :src="saveIcon" alt="save icon" />
<div class="bar"></div>
</button>
</div>
</section>
</template>
@@ -19,20 +24,24 @@
import { defineComponent } from 'vue';
import { useStore } from '../store/store';
import saveIcon from '../assets/icon-save.svg';
export default defineComponent({
data() {
return {
saveIcon,
orderTypeList: [
{
id: 'OrderN',
id: 'orderN',
name: 'N',
},
{
id: 'OrderS',
id: 'orderS',
name: 'S',
},
{
id: 'OrderO',
id: 'orderO',
name: 'O',
},
],
@@ -45,9 +54,13 @@ export default defineComponent({
},
methods: {
selectOrderType(type: string) {
selectOrderType(type: any) {
this.store.chosenOrderType = type;
},
toggleOrderMode() {
this.store.orderMode = this.store.orderMode == 'OrderMessage' ? 'OrderList' : 'OrderMessage';
},
},
});
</script>
@@ -67,7 +80,7 @@ export default defineComponent({
.sidebar_content {
display: grid;
grid-template-rows: repeat(3, 1fr);
grid-template-rows: repeat(4, 1fr);
gap: 0.25em;
font-size: 1.5em;
@@ -111,6 +124,19 @@ export default defineComponent({
}
}
button.option-save {
background-color: $accentCol;
img {
width: 80%;
height: 80%;
}
&[data-selected='true'] .bar {
background-color: #111;
}
}
@media screen and (max-width: 650px) {
.sidebar {
left: 50%;
@@ -121,10 +147,10 @@ export default defineComponent({
.sidebar_content {
grid-template-rows: 1fr;
grid-template-columns: repeat(3, 1fr);
grid-template-columns: repeat(4, 1fr);
& > button {
height: 50px;
height: 60px;
width: 60px;
.bar {
+59
View File
@@ -0,0 +1,59 @@
import { defineComponent } from 'vue';
import { useStore } from '../store/store';
import { LocalStorageOrder } from '../types/orderTypes';
export default defineComponent({
setup() {
return {
store: useStore(),
};
},
methods: {
saveOrderToStorage() {
let orderObj: LocalStorageOrder = {
orderType: this.store.chosenOrderType ,
orderBody: {},
orderFooter: this.store.orderFooter,
createdAt: Date.now(),
};
switch (this.store.chosenOrderType) {
case 'orderN':
orderObj['orderBody'] = this.store.orderN;
break;
case 'orderS':
orderObj['orderBody'] = this.store.orderS;
break;
case 'orderO':
orderObj['orderBody'] = this.store.orderO;
break;
default:
break;
}
const headerInfo = orderObj['orderBody']['header'];
if (!headerInfo['orderNo']) return -1;
if (!headerInfo['trainNo']) return -1;
if (!headerInfo['date']) return -1;
const localStorage = window.localStorage;
const localOrderCount = localStorage.getItem('orderCount') || '0';
if (localOrderCount == '0') localStorage.setItem('orderCount', '0');
const prevLocalOrder = localStorage.getItem(`order-${Number(localOrderCount)}`);
if (prevLocalOrder && prevLocalOrder == JSON.stringify(orderObj)) {
return 0;
}
const nextOrderCount = Number(localOrderCount) + 1;
localStorage.setItem('orderCount', `${nextOrderCount}`);
localStorage.setItem(`order-${nextOrderCount}`, JSON.stringify(orderObj));
return 1;
},
},
});
+3 -1
View File
@@ -3,7 +3,8 @@ import { defineStore } from 'pinia';
export const useStore = defineStore('store', {
state: () => {
return {
chosenOrderType: 'OrderN',
chosenOrderType: 'orderN' as 'orderO' | 'orderS' | 'orderN',
orderMode: 'OrderMessage',
orderFooter: {
stationName: '',
@@ -180,3 +181,4 @@ export const useStore = defineStore('store', {
});
+28 -6
View File
@@ -1,7 +1,8 @@
@import url('https://fonts.googleapis.com/css2?family=Libre+Franklin:wght@400;600&display=swap');
$bgCol: #313638;
$accentCol: #0defff;
$accentCol: #ff6060;
$warnCol: #ffe02e;
body,
html {
@@ -36,16 +37,24 @@ button {
padding: 0.5em;
}
&:hover {
color: $accentCol;
}
&:focus-visible {
outline: 2px solid $accentCol;
color: $accentCol;
}
}
// Text styles
.text {
&--accent {
color: $accentCol;
}
&--warn {
color: $warnCol;
}
}
// Select style
select {
border: 2px solid black;
background: none;
@@ -54,7 +63,20 @@ select {
text-align: center;
}
// Global scrollbar
// List style
ul {
padding: 0;
margin: 0;
list-style: none;
text-align: center;
li {
padding: 0.5em;
}
}
// Global scrollbar style
::-webkit-scrollbar {
width: 10px;
}
+6
View File
@@ -0,0 +1,6 @@
export interface LocalStorageOrder {
orderType: 'orderO' | 'orderS' | 'orderN';
orderBody: any;
orderFooter: any;
createdAt: number;
}
+19 -57
View File
@@ -8,14 +8,11 @@
</div>
<div class="message_container">
<h3>Wiadomość do wyświetlenia na czacie symulatora:</h3>
<div class="message_body" v-html="fullOrderMessage"></div>
<div class="message_actions">
<button class="g-button" @click="copyMessage">Zapisz ten rozkaz</button>
<button class="g-button" @click="copyMessage">Kopiuj wiadomość rozkazu</button>
</div>
<transition name="order-anim" mode="out-in">
<keep-alive>
<Component :is="orderModeComponent" />
</keep-alive>
</transition>
</div>
</div>
</div>
@@ -24,8 +21,11 @@
<script lang="ts">
import { defineComponent } from 'vue';
import OrderVue from '../components/Order.vue';
import { useStore } from '../store/store';
import SideBar from '../components/SideBar.vue';
import OrderMessage from '../components/OrderMessage.vue';
import OrderList from '../components/OrderList.vue';
import { useStore } from '../store/store';
export default defineComponent({
components: { OrderVue, SideBar },
@@ -36,14 +36,15 @@ export default defineComponent({
},
computed: {
fullOrderMessage() {
return this.store.orderMessage + this.store.footerMessage;
},
},
methods: {
copyMessage() {
navigator.clipboard.writeText(this.fullOrderMessage);
orderModeComponent() {
switch (this.store.orderMode) {
case 'OrderMessage':
return OrderMessage;
case 'OrderList':
return OrderList;
default:
return OrderMessage;
}
},
},
});
@@ -63,7 +64,7 @@ export default defineComponent({
margin-top: 1em;
@media screen and (max-width: 650px) {
margin-top: 60px;
margin-top: 80px;
}
}
@@ -77,43 +78,4 @@ export default defineComponent({
}
}
}
.message_container {
padding: 1em;
width: 500px;
h3 {
margin: 0;
margin-bottom: 1em;
text-align: center;
}
button {
margin: 0 0.5em;
}
@media screen and (max-width: 550px) {
max-width: 100%;
}
}
.message_actions {
display: flex;
justify-content: center;
margin-top: 1em;
}
.message_body {
height: 250px;
overflow: auto;
text-align: justify;
background-color: #fff;
border-radius: 0.5em;
color: black;
padding: 0.5em;
user-select: none;
-moz-user-select: none;
-webkit-user-select: none;
}
</style>