118 lines
3.9 KiB
Vue
118 lines
3.9 KiB
Vue
<template>
|
|
<input v-model="inputSerial" type="text" :id="id" :required="required" class="form-control" :class="inputClass" />
|
|
<BootstrapAlert show :variant="formatShow" v-if="formatHint">{{ formatHint }}</BootstrapAlert>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import BootstrapAlert from './BootstrapAlert.vue';
|
|
import { defineComponent } from 'vue';
|
|
|
|
const chars32 = '0123456789ABCDEFGHJKLMNPRSTUVWXY';
|
|
|
|
export default defineComponent({
|
|
components: {
|
|
BootstrapAlert,
|
|
},
|
|
props: {
|
|
modelValue: { type: [String, Number], required: true },
|
|
id: String,
|
|
inputClass: String,
|
|
required: Boolean,
|
|
},
|
|
data() {
|
|
return {
|
|
inputSerial: '',
|
|
formatHint: '',
|
|
formatShow: 'info',
|
|
};
|
|
},
|
|
computed: {
|
|
model: {
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
get(): any {
|
|
return this.modelValue;
|
|
},
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
set(value: any) {
|
|
this.$emit('update:modelValue', value);
|
|
},
|
|
},
|
|
},
|
|
watch: {
|
|
modelValue: function (val) {
|
|
this.inputSerial = val;
|
|
},
|
|
inputSerial: function (val) {
|
|
const serial = val.toString().toUpperCase(); // Convert to lowercase for case-insensitivity
|
|
|
|
if (serial == '') {
|
|
this.formatHint = '';
|
|
this.model = '';
|
|
return;
|
|
}
|
|
|
|
this.formatShow = 'info';
|
|
|
|
// Contains only numbers
|
|
if (/^1{1}[\dA-F]{11}$/.test(serial)) {
|
|
this.model = serial;
|
|
this.formatHint = this.$t('inputserial.format_hoymiles');
|
|
}
|
|
|
|
// Contains numbers and hex characters but at least one number
|
|
else if (/^(?=.*\d)[\dA-F]{12}$/.test(serial)) {
|
|
this.model = serial;
|
|
this.formatHint = this.$t('inputserial.format_converted');
|
|
}
|
|
|
|
// Has format: xxxxxxxxx-xxx
|
|
else if (/^((A01)|(A11)|(A21))[\dA-HJ-NR-YP]{6}-[\dA-HJ-NP-Z]{3}$/.test(serial)) {
|
|
if (this.checkHerfChecksum(serial)) {
|
|
this.model = this.convertHerfToHoy(serial);
|
|
this.$nextTick(() => {
|
|
this.formatHint = this.$t('inputserial.format_herf_valid', {
|
|
serial: this.model,
|
|
});
|
|
});
|
|
} else {
|
|
this.formatHint = this.$t('inputserial.format_herf_invalid');
|
|
this.formatShow = 'danger';
|
|
}
|
|
|
|
// Any other format
|
|
} else {
|
|
this.formatHint = this.$t('inputserial.format_unknown');
|
|
this.formatShow = 'danger';
|
|
}
|
|
},
|
|
},
|
|
methods: {
|
|
checkHerfChecksum(sn: string) {
|
|
const chars64 = 'HMFLGW5XC301234567899Z67YRT2S8ABCDEFGHJKDVEJ4KQPUALMNPRSTUVWXYNB';
|
|
|
|
const checksum = sn.substring(sn.indexOf('-') + 1);
|
|
const serial = sn.substring(0, sn.indexOf('-'));
|
|
|
|
const first_char = '1';
|
|
const i = chars32.indexOf(first_char);
|
|
const sum1: number = Array.from(serial).reduce((sum, c) => sum + c.charCodeAt(0), 0) & 31;
|
|
const sum2: number = Array.from(serial).reduce((sum, c) => sum + chars32.indexOf(c), 0) & 31;
|
|
const ext = first_char + chars64[sum1 + i] + chars64[sum2 + i];
|
|
|
|
return checksum == ext;
|
|
},
|
|
convertHerfToHoy(sn: string) {
|
|
let sn_int: bigint = 0n;
|
|
|
|
for (let i = 0; i < 9; i++) {
|
|
const pos: bigint = BigInt(chars32.indexOf(sn[i].toUpperCase()));
|
|
const shift: bigint = BigInt(42 - 5 * i - (i <= 2 ? 0 : 2));
|
|
sn_int |= pos << shift;
|
|
}
|
|
|
|
return sn_int.toString(16);
|
|
},
|
|
},
|
|
});
|
|
</script>
|