chore: added generating message text for custom instructions

This commit is contained in:
2025-09-27 14:49:23 +02:00
parent 9118c186cf
commit fa4504fec7
5 changed files with 302 additions and 199 deletions
+111 -84
View File
@@ -1,13 +1,10 @@
<template> <template>
<table class="order-table"> <table class="order-table">
<tbody> <tbody>
<!-- First row - 22 & 99 instructions -->
<tr> <tr>
<td width="10%" class="order-instruction-number"> <td width="10%" class="order-instruction-number">
<label class="order-instruction-checkbox"> <OrderRowCheckbox :row-index="0" />
<input type="checkbox" v-model="store.orderData.instructions[0].active" />
<div class="checkmark"></div>
<div class="text">22</div>
</label>
</td> </td>
<td> <td>
@@ -17,11 +14,7 @@
</td> </td>
<td width="5%" class="order-instruction-number"> <td width="5%" class="order-instruction-number">
<label class="order-instruction-checkbox"> <OrderRowCheckbox :row-index="1" />
<input type="checkbox" v-model="store.orderData.instructions[1].active" />
<div class="checkmark"></div>
<div class="text">99</div>
</label>
</td> </td>
<td width="45%"> <td width="45%">
@@ -39,88 +32,53 @@
</tr> </tr>
<!-- From 21.10 --> <!-- From 21.10 -->
<tr v-for="(instruction, i) in store.orderData.instructions.slice(2)"> <tr
v-for="(instruction, i) in store.orderData.instructions.slice(2)"
:style="{
'background-color': instruction.key.startsWith('218') ? '#eeece1' : 'inherit'
}"
>
<td width="10%" class="order-instruction-number"> <td width="10%" class="order-instruction-number">
<label class="order-instruction-checkbox"> <OrderRowCheckbox :row-index="i + 2" />
<input type="checkbox" v-model="instruction.active" />
<div class="checkmark"></div>
<div class="text">{{ instruction.name }}</div>
</label>
</td> </td>
<td colspan="3"> <td colspan="3">
<i18n-t :keypath="`order.${instruction.key}.text`" tag="div"> <i18n-t :keypath="`order.${instruction.key}.text`" tag="div" scope="global">
<!-- For all instructions with text directives --> <!-- For text directives (<b>, <u>, <br> etc.) -->
<template v-slot:bold1> <template v-slot:[directive] v-for="directive in instruction.textDirectives">
<b>{{ t(`order.${instruction.key}.bold1`) }}</b> <b v-if="directive.startsWith('bold')">
</template> {{ t(`order.${instruction.key}.${directive}`) }}
</b>
<template v-slot:bold2> <u v-else-if="directive.startsWith('underline')">
<b>{{ t(`order.${instruction.key}.bold2`) }}</b> {{ t(`order.${instruction.key}.${directive}`) }}
</template>
<template v-slot:underline1>
<u>{{ t(`order.${instruction.key}.underline1`) }}</u>
</template>
<template v-slot:highlight1>
<u>
<b>{{ t(`order.${instruction.key}.highlight1`) }}</b>
</u> </u>
</template> <u v-else-if="directive.startsWith('highlight')">
<b>{{ t(`order.${instruction.key}.${directive}`) }}</b>
<template v-slot:highlight2>
<u>
<b>{{ t(`order.${instruction.key}.highlight2`) }}</b>
</u> </u>
</template> <br v-if="directive.startsWith('br')" />
<template v-slot:br>
<br />
</template>
<!-- For 23.10 only -->
<template v-slot:text-list v-if="instruction.key == '2310'">
<i18n-t
v-for="(fieldInputs, i) in instruction.listFields"
:keypath="`order.${instruction.key}.text-list`"
tag="div"
>
<template v-slot:bold>
<label>
<input type="checkbox" />
<b>{{ t(`order.${instruction.key}.bold`, [i + 1]) }}</b>
</label>
</template>
<template v-slot:v>
<br />
<span style="font-size: 1.5em">v</span>
</template>
<template v-slot:[fieldKey] v-for="(_, fieldKey, j) in fieldInputs">
<input
class="order-input"
:id="`order-${instruction.key}-${fieldKey}`"
:style="{ width: calculateInputWidthByFieldName(fieldKey) }"
v-model="instruction.listFields![i][fieldKey]"
:placeholder="
t(`order.${instruction.key}.${fieldKey}`, [j + 1 + 6 * i, 91 + i])
"
/>
</template>
</i18n-t>
</template> </template>
<!-- For all instructions with input fields --> <!-- For all instructions with input fields -->
<template v-slot:[fieldKey] v-for="(_, fieldKey) in instruction.inputFields"> <template v-slot:[fieldKey] v-for="(_, fieldKey) in instruction.inputFields">
<textarea
v-if="fieldKey == 'other2320'"
v-model="instruction.inputFields[fieldKey]"
class="order-textarea"
:id="`order-${instruction.key}-${fieldKey}`"
:placeholder="t(`order.${instruction.key}.${fieldKey}`)"
autocomplete="off"
></textarea>
<label class="order-input-box" v-else>
<input <input
v-model="instruction.inputFields[fieldKey]"
class="order-input" class="order-input"
:id="`order-${instruction.key}-${fieldKey}`" :id="`order-${instruction.key}-${fieldKey}`"
:style="{ width: calculateInputWidthByFieldName(fieldKey) }" :style="{ width: calculateInputWidthByFieldName(fieldKey) }"
v-model="instruction.inputFields[fieldKey]" autocomplete="off"
:placeholder="t(`order.${instruction.key}.${fieldKey}`)"
/> />
<span>{{ t(`order.${instruction.key}.${fieldKey}`) }}</span>
</label>
</template> </template>
<!-- For all instructions with select fields --> <!-- For all instructions with select fields -->
@@ -135,6 +93,48 @@
</option> </option>
</select> </select>
</template> </template>
<!-- For 23.10 only -->
<template v-slot:text-list v-if="instruction.key == '2310'">
<i18n-t
v-for="(listItem, i) in instruction.listFields"
:keypath="`order.${instruction.key}.text-list`"
tag="div"
scope="global"
>
<template v-slot:bold>
<label>
<input
v-model="listItem.active"
type="checkbox"
:id="`order-${instruction.key}-checkbox`"
/>
&nbsp;
<b>{{ t(`order.${instruction.key}.bold`, [i + 1]) }}</b>
</label>
</template>
<template v-slot:v>
<br />
<span style="font-size: 1.5em">v</span>
</template>
<template v-slot:[fieldKey] v-for="(_, fieldKey, j) in listItem.values">
<label class="order-input-box">
<input
v-model="instruction.listFields![i]['values'][fieldKey]"
class="order-input"
:id="`order-${instruction.key}-${fieldKey}-${i}`"
:style="{ width: calculateInputWidthByFieldName(fieldKey) }"
autocomplete="off"
/>
<span>{{
t(`order.${instruction.key}.${fieldKey}`, [j + 1 + 6 * i, 91 + i])
}}</span>
</label>
</template>
</i18n-t>
</template>
</i18n-t> </i18n-t>
</td> </td>
</tr> </tr>
@@ -146,6 +146,7 @@
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useStore } from '../../store/store'; import { useStore } from '../../store/store';
import { onMounted, watch } from 'vue'; import { onMounted, watch } from 'vue';
import OrderRowCheckbox from './OrderRowCheckbox.vue';
const { t } = useI18n(); const { t } = useI18n();
const store = useStore(); const store = useStore();
@@ -164,8 +165,11 @@ watch(
function calculateInputWidthByFieldName(fieldName: string) { function calculateInputWidthByFieldName(fieldName: string) {
if (fieldName.startsWith('track')) return '90px'; if (fieldName.startsWith('track')) return '90px';
else if (fieldName.startsWith('signalbox')) return '150px'; else if (fieldName.startsWith('signalbox')) return '130px';
else if (fieldName.startsWith('signal')) return '150px'; else if (fieldName.startsWith('signal')) return '150px';
else if (fieldName.startsWith('train')) return '150px';
else if (fieldName.startsWith('other2320')) return '100%';
else if (fieldName.startsWith('other')) return '200px';
return '100px'; return '100px';
} }
@@ -176,11 +180,10 @@ function generateMessage() {
const headerData = store.orderData['header']; const headerData = store.orderData['header'];
Object.entries(headerData).forEach(([key, value]) => { messageHtml += `${t('order.header.A')}: ${headerData['A']}<br />`;
messageHtml += `${t('order.header.' + key)}: ${value}<br />`; messageHtml += `${t('order.header.B')}: ${headerData['B']}<br />`;
}); messageHtml += `${t('order.header.C')}: ${headerData['C']}<br />`;
messageHtml += `${t('order.header.D')}: ${headerData['D']}<br />`;
messageHtml += '-------------<br />';
const instructions = store.orderData['instructions']; const instructions = store.orderData['instructions'];
@@ -195,16 +198,40 @@ function generateMessage() {
return fieldKey || '---'; return fieldKey || '---';
}); });
messageHtml += '-------------<br />';
messageHtml += `<b>[${value.name}]</b> ${t( messageHtml += `<b>[${value.name}]</b> ${t(
localeKey + '.message-html', localeKey + '.message-html',
messageValues messageValues
)}<br />`; )}<br />`;
if (value.key == '2310' && value.listFields) {
messageHtml += '<br />';
value.listFields.forEach((listItem, i) => {
if (!listItem.active) return;
const listItemValues = Object.values(listItem.values).map((itemFieldKey) => {
return itemFieldKey || '---';
});
messageHtml += t(`${localeKey}.message-html-list`, [i + 1, ...listItemValues]);
messageHtml += '<br />';
});
}
} else { } else {
messageHtml += `<b>[${i}]</b> ${t('order.' + i + '.message-html')}<br />`; messageHtml += `<b>[${i}]</b> ${t('order.' + i + '.message-html')}<br />`;
} }
} }
}); });
const footerData = store.orderData['footer'];
messageHtml += '-------------<br />';
messageHtml += `${t('order.footer.V')}: ${footerData['V'] || '---'} | `;
messageHtml += `${t('order.footer.W')}: ${footerData['W'] || '---'}<br />`;
messageHtml += `${t('order.footer.Y')}: ${footerData['Y'] || '---'} | `;
messageHtml += `${t('order.footer.Z')}: ${footerData['Z'] || '---'}<br />`;
store.orderMessage = messageHtml; store.orderMessage = messageHtml;
} }
</script> </script>
@@ -227,7 +254,7 @@ function generateMessage() {
.order-instruction-number { .order-instruction-number {
position: relative; position: relative;
height: 65px; height: 60px;
& > label { & > label {
position: absolute; position: absolute;
+81
View File
@@ -0,0 +1,81 @@
<template>
<label class="order-instruction-checkbox">
<input type="checkbox" v-model="instructionObject.active" />
<div class="checkmark"></div>
<div class="text">{{ instructionObject.name }}</div>
</label>
</template>
<script setup lang="ts">
import { computed } from 'vue';
import { useStore } from '../../store/store';
const store = useStore();
const props = defineProps({
rowIndex: {
type: Number,
required: true
}
});
const instructionObject = computed(() => store.orderData.instructions[props.rowIndex]);
</script>
<style lang="scss" scoped>
.order-instruction-checkbox {
display: block;
position: relative;
text-align: center;
cursor: pointer;
font-weight: bold;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
& > input {
position: absolute;
opacity: 0;
height: 0;
width: 0;
cursor: pointer;
&:checked ~ .checkmark:after {
content: 'X';
}
&:focus-visible ~ .text {
text-decoration: underline;
outline: 1px solid black;
}
}
.checkmark {
display: block;
position: relative;
margin: 0 auto;
height: 1.3em;
width: 1.3em;
background-color: #eee;
border: 2px solid black;
background-color: gold;
&:after {
position: absolute;
content: '';
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}
&:hover input ~ .checkmark {
background-color: #ffe44b;
}
}
</style>
+2 -1
View File
@@ -245,7 +245,8 @@
"km1": "x.{0} km", "km1": "x.{0} km",
"km2": "x.{0} km", "km2": "x.{0} km",
"other1": "x.{1} przyczyna", "other1": "x.{1} przyczyna",
"message-html": "<b>Nie przekraczać prędkości i zachować ostrożność:</b> <br /> " "message-html": "<b>Nie przekraczać prędkości i zachować ostrożność:</b>",
"message-html-list": "<b>{0}. Na posterunku/szlaku</b> {1}/{2} tor nr {3} v{4} od {5}km do {6}km - przyczyna: {7}"
}, },
"2311": { "2311": {
"text": "{bold1}", "text": "{bold1}",
+86 -49
View File
@@ -37,7 +37,8 @@ export const useStore = defineStore('store', {
name: '22', name: '22',
active: false, active: false,
inputFields: {}, inputFields: {},
optionalFieldNames: [] optionalFieldNames: [],
textDirectives: []
}, },
{ {
key: '99', key: '99',
@@ -46,7 +47,8 @@ export const useStore = defineStore('store', {
inputFields: { inputFields: {
x1: '' x1: ''
}, },
optionalFieldNames: [] optionalFieldNames: [],
textDirectives: []
}, },
{ {
key: '2110', key: '2110',
@@ -61,7 +63,8 @@ export const useStore = defineStore('store', {
signal2: '', signal2: '',
signal3: '' signal3: ''
}, },
optionalFieldNames: ['signal1', 'signal2', 'signal3'] optionalFieldNames: ['signal1', 'signal2', 'signal3'],
textDirectives: ['bold1', 'br']
}, },
{ {
key: '2115', key: '2115',
@@ -75,7 +78,8 @@ export const useStore = defineStore('store', {
signal2: '', signal2: '',
signal3: '' signal3: ''
}, },
optionalFieldNames: ['signal1', 'signal2', 'signal3'] optionalFieldNames: ['signal1', 'signal2', 'signal3'],
textDirectives: ['bold1', 'br']
}, },
{ {
key: '2120', key: '2120',
@@ -85,7 +89,9 @@ export const useStore = defineStore('store', {
track1: '', track1: '',
signalbox1: '', signalbox1: '',
signalbox2: '' signalbox2: ''
} },
optionalFieldNames: [],
textDirectives: ['highlight1', 'highlight2', 'underline1', 'br']
}, },
{ {
key: '2125', key: '2125',
@@ -102,7 +108,9 @@ export const useStore = defineStore('store', {
select1: { select1: {
options: ['select1-a', 'select1-b'] options: ['select1-a', 'select1-b']
} }
} },
optionalFieldNames: [],
textDirectives: []
}, },
{ {
key: '2135', key: '2135',
@@ -111,7 +119,9 @@ export const useStore = defineStore('store', {
inputFields: { inputFields: {
track1: '', track1: '',
signalbox1: '' signalbox1: ''
} },
optionalFieldNames: [],
textDirectives: ['bold1']
}, },
{ {
key: '2140', key: '2140',
@@ -123,7 +133,8 @@ export const useStore = defineStore('store', {
km1: '', km1: '',
other1: '' other1: ''
}, },
optionalFieldNames: ['signalbox2'] optionalFieldNames: ['signalbox2'],
textDirectives: ['bold1']
}, },
{ {
key: '2145', key: '2145',
@@ -132,7 +143,9 @@ export const useStore = defineStore('store', {
inputFields: { inputFields: {
signalbox1: '', signalbox1: '',
signal1: '' signal1: ''
} },
optionalFieldNames: [],
textDirectives: ['bold1']
}, },
{ {
key: '2150', key: '2150',
@@ -143,7 +156,8 @@ export const useStore = defineStore('store', {
signalbox2: '', signalbox2: '',
km1: '' km1: ''
}, },
optionalFieldNames: ['signalbox2'] optionalFieldNames: ['signalbox2'],
textDirectives: ['bold1', 'br']
}, },
{ {
key: '2155', key: '2155',
@@ -154,7 +168,8 @@ export const useStore = defineStore('store', {
signalbox2: '', signalbox2: '',
signal1: '' signal1: ''
}, },
optionalFieldNames: ['signalbox2'] optionalFieldNames: ['signalbox2'],
textDirectives: ['bold1']
}, },
{ {
key: '2160', key: '2160',
@@ -166,7 +181,9 @@ export const useStore = defineStore('store', {
signalbox3: '', signalbox3: '',
line1: '', line1: '',
vmax1: '' vmax1: ''
} },
optionalFieldNames: [],
textDirectives: ['bold1']
}, },
{ {
key: '2165', key: '2165',
@@ -175,7 +192,9 @@ export const useStore = defineStore('store', {
inputFields: { inputFields: {
km1: '', km1: '',
km2: '' km2: ''
} },
optionalFieldNames: [],
textDirectives: ['bold1']
}, },
{ {
key: '2170', key: '2170',
@@ -185,7 +204,9 @@ export const useStore = defineStore('store', {
signalbox1: '', signalbox1: '',
signalbox2: '', signalbox2: '',
line1: '' line1: ''
} },
optionalFieldNames: [],
textDirectives: ['bold1', 'br']
}, },
{ {
key: '2180', key: '2180',
@@ -197,13 +218,17 @@ export const useStore = defineStore('store', {
km1: '', km1: '',
signalbox2: '', signalbox2: '',
hour1: '' hour1: ''
} },
optionalFieldNames: [],
textDirectives: ['bold1']
}, },
{ {
key: '2181', key: '2181',
name: '21.81', name: '21.81',
active: false, active: false,
inputFields: {} inputFields: {},
optionalFieldNames: [],
textDirectives: ['bold1']
}, },
{ {
key: '2182', key: '2182',
@@ -212,7 +237,9 @@ export const useStore = defineStore('store', {
inputFields: { inputFields: {
train1: '', train1: '',
km1: '' km1: ''
} },
optionalFieldNames: [],
textDirectives: ['bold1']
}, },
{ {
key: '2183', key: '2183',
@@ -221,7 +248,9 @@ export const useStore = defineStore('store', {
inputFields: { inputFields: {
train1: '', train1: '',
km1: '' km1: ''
} },
optionalFieldNames: [],
textDirectives: ['bold1']
}, },
{ {
key: '2185', key: '2185',
@@ -232,7 +261,9 @@ export const useStore = defineStore('store', {
km1: '', km1: '',
signalbox1: '', signalbox1: '',
signalbox2: '' signalbox2: ''
} },
optionalFieldNames: [],
textDirectives: ['bold1']
}, },
{ {
key: '2310', key: '2310',
@@ -241,24 +272,8 @@ export const useStore = defineStore('store', {
inputFields: {}, inputFields: {},
listFields: [ listFields: [
{ {
signalbox1: '', active: false,
signalbox2: '', values: {
track1: '',
vmax1: '',
km1: '',
km2: '',
other1: ''
},
{
signalbox1: '',
signalbox2: '',
track1: '',
vmax1: '',
km1: '',
km2: '',
other1: ''
},
{
signalbox1: '', signalbox1: '',
signalbox2: '', signalbox2: '',
track1: '', track1: '',
@@ -267,13 +282,42 @@ export const useStore = defineStore('store', {
km2: '', km2: '',
other1: '' other1: ''
} }
] },
{
active: false,
values: {
signalbox1: '',
signalbox2: '',
track1: '',
vmax1: '',
km1: '',
km2: '',
other1: ''
}
},
{
active: false,
values: {
signalbox1: '',
signalbox2: '',
track1: '',
vmax1: '',
km1: '',
km2: '',
other1: ''
}
}
],
optionalFieldNames: [],
textDirectives: ['bold1', 'br']
}, },
{ {
key: '2311', key: '2311',
name: '23.11', name: '23.11',
active: false, active: false,
inputFields: {} inputFields: {},
optionalFieldNames: [],
textDirectives: ['bold1']
}, },
{ {
key: '2320', key: '2320',
@@ -281,18 +325,11 @@ export const useStore = defineStore('store', {
active: false, active: false,
inputFields: { inputFields: {
other2320: '' other2320: ''
} },
optionalFieldNames: [],
textDirectives: []
} }
], ],
customInstructions: {
'2310': {
name: '23.10',
active: false,
inputFields: {},
optionalFieldNames: []
}
},
footer: { footer: {
V: '', V: '',
W: '', W: '',
+16 -59
View File
@@ -29,13 +29,28 @@ table.order-table {
td { td {
border: 2px solid black; border: 2px solid black;
border-collapse: collapse; border-collapse: collapse;
line-height: 1.25em;
text-align: justify; text-align: justify;
vertical-align: top; vertical-align: top;
} }
} }
.order-input-box {
display: inline-block;
position: relative;
padding-bottom: 1.25em;
& > span {
position: absolute;
left: 50%;
top: 0;
transform: translate(-50%, 2em);
font-size: 0.8em;
width: 100%;
text-align: center;
}
}
input.order-input { input.order-input {
max-width: 100%; max-width: 100%;
background-color: transparent; background-color: transparent;
@@ -134,61 +149,3 @@ textarea.order-textarea {
border-color: $darkModeTextCol !important; border-color: $darkModeTextCol !important;
} }
} }
/* Instruction Checkbox */
.order-instruction-checkbox {
display: block;
position: relative;
text-align: center;
cursor: pointer;
font-weight: bold;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
& > input {
position: absolute;
opacity: 0;
height: 0;
width: 0;
cursor: pointer;
&:checked ~ .checkmark:after {
content: 'X';
}
&:focus-visible ~ .text {
text-decoration: underline;
outline: 1px solid black;
}
}
.checkmark {
display: block;
position: relative;
margin: 0 auto;
margin-bottom: 0.35em;
height: 1.3em;
width: 1.3em;
background-color: #eee;
border: 2px solid black;
background-color: gold;
&:after {
position: absolute;
content: '';
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}
&:hover input ~ .checkmark {
background-color: #ffe44b;
}
}