Files
ezbookkeeping/src/components/mobile/NumberPadSheet.vue
T
2023-07-02 00:51:26 +08:00

413 lines
14 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<f7-sheet swipe-to-close swipe-handler=".swipe-handler" class="numpad-sheet" style="height: auto"
:opened="show" @sheet:open="onSheetOpen" @sheet:closed="onSheetClosed">
<div class="swipe-handler" style="z-index: 10"></div>
<f7-page-content class="margin-top no-padding-top">
<div class="numpad-values">
<span class="numpad-value" :class="currentDisplayNumClass">{{ currentDisplay }}</span>
</div>
<div class="numpad-buttons">
<f7-button class="numpad-button numpad-button-num" @click="inputNum(7)">
<span class="numpad-button-text numpad-button-text-normal">7</span>
</f7-button>
<f7-button class="numpad-button numpad-button-num" @click="inputNum(8)">
<span class="numpad-button-text numpad-button-text-normal">8</span>
</f7-button>
<f7-button class="numpad-button numpad-button-num" @click="inputNum(9)">
<span class="numpad-button-text numpad-button-text-normal">9</span>
</f7-button>
<f7-button class="numpad-button numpad-button-function no-right-border" @click="setSymbol('×')">
<span class="numpad-button-text numpad-button-text-normal">&times;</span>
</f7-button>
<f7-button class="numpad-button numpad-button-num" @click="inputNum(4)">
<span class="numpad-button-text numpad-button-text-normal">4</span>
</f7-button>
<f7-button class="numpad-button numpad-button-num" @click="inputNum(5)">
<span class="numpad-button-text numpad-button-text-normal">5</span>
</f7-button>
<f7-button class="numpad-button numpad-button-num" @click="inputNum(6)">
<span class="numpad-button-text numpad-button-text-normal">6</span>
</f7-button>
<f7-button class="numpad-button numpad-button-function no-right-border" @click="setSymbol('')">
<span class="numpad-button-text numpad-button-text-normal">&minus;</span>
</f7-button>
<f7-button class="numpad-button numpad-button-num" @click="inputNum(1)">
<span class="numpad-button-text numpad-button-text-normal">1</span>
</f7-button>
<f7-button class="numpad-button numpad-button-num" @click="inputNum(2)">
<span class="numpad-button-text numpad-button-text-normal">2</span>
</f7-button>
<f7-button class="numpad-button numpad-button-num" @click="inputNum(3)">
<span class="numpad-button-text numpad-button-text-normal">3</span>
</f7-button>
<f7-button class="numpad-button numpad-button-function no-right-border" @click="setSymbol('+')">
<span class="numpad-button-text numpad-button-text-normal">&plus;</span>
</f7-button>
<f7-button class="numpad-button numpad-button-num" @click="inputDot()">
<span class="numpad-button-text numpad-button-text-normal">.</span>
</f7-button>
<f7-button class="numpad-button numpad-button-num" @click="inputNum(0)">
<span class="numpad-button-text numpad-button-text-normal">0</span>
</f7-button>
<f7-button class="numpad-button numpad-button-num" @click="backspace" @taphold="clear()">
<span class="numpad-button-text numpad-button-text-normal">
<f7-icon f7="delete_left"></f7-icon>
</span>
</f7-button>
<f7-button class="numpad-button numpad-button-confirm no-right-border no-bottom-border" fill @click="confirm()">
<span :class="{ 'numpad-button-text': true, 'numpad-button-text-confirm': !currentSymbol }">{{ confirmText }}</span>
</f7-button>
</div>
</f7-page-content>
</f7-sheet>
</template>
<script>
import { mapStores } from 'pinia';
import { useSettingsStore } from '@/stores/setting.js';
import { isString, appendThousandsSeparator } from '@/lib/common.js';
import { numericCurrencyToString, stringCurrencyToNumeric } from '@/lib/currency.js';
export default {
props: [
'modelValue',
'minValue',
'maxValue',
'show'
],
emits: [
'update:modelValue',
'update:show'
],
data() {
const self = this;
return {
previousValue: '',
currentSymbol: '',
currentValue: self.getStringValue(self.modelValue)
}
},
computed: {
...mapStores(useSettingsStore),
isEnableThousandsSeparator() {
return this.settingsStore.appSettings.thousandsSeparator;
},
currentDisplay() {
const previousValue = appendThousandsSeparator(this.previousValue, this.isEnableThousandsSeparator);
const currentValue = appendThousandsSeparator(this.currentValue, this.isEnableThousandsSeparator);
if (this.currentSymbol) {
return `${previousValue} ${this.currentSymbol} ${currentValue}`;
} else {
return currentValue;
}
},
currentDisplayNumClass() {
const currentDisplay = this.currentDisplay || '';
if (currentDisplay.length >= 24) {
return 'numpad-value-small';
} else if (currentDisplay.length >= 16) {
return 'numpad-value-normal';
} else {
return 'numpad-value-large';
}
},
confirmText() {
if (this.currentSymbol) {
return '=';
} else {
return this.$t('OK');
}
}
},
methods: {
getStringValue(value) {
let str = numericCurrencyToString(value, this.isEnableThousandsSeparator);
if (str.indexOf(',')) {
str = str.replaceAll(/,/g, '');
}
const dotPos = str.indexOf('.');
if (dotPos < 0) {
if (str === '0') {
return '';
}
return str;
}
let integer = str.substring(0, dotPos);
let decimals = str.substring(dotPos + 1, str.length);
let newDecimals = '';
for (let i = decimals.length - 1; i >= 0; i--) {
if (decimals[i] !== '0' || newDecimals.length > 0) {
newDecimals = decimals[i] + newDecimals;
}
}
if (newDecimals.length < 1) {
if (integer === '0') {
return '';
}
return integer;
}
return `${integer}.${newDecimals}`;
},
inputNum(num) {
if (!this.previousValue && this.currentSymbol === '') {
this.currentValue = '-' + this.currentValue;
this.currentSymbol = '';
}
if (this.currentValue === '0') {
this.currentValue = num.toString();
return;
} else if (this.currentValue === '-0') {
this.currentValue = '-' + num.toString();
return;
}
const dotPos = this.currentValue.indexOf('.');
if (dotPos >= 0 && this.currentValue.substring(dotPos + 1, this.currentValue.length).length >= 2) {
return;
}
const newValue = this.currentValue + num.toString();
if (isString(this.minValue) && this.minValue !== '') {
const min = stringCurrencyToNumeric(this.minValue);
const current = stringCurrencyToNumeric(newValue);
if (current < min) {
return;
}
}
if (isString(this.maxValue) && this.maxValue !== '') {
const max = stringCurrencyToNumeric(this.maxValue);
const current = stringCurrencyToNumeric(newValue);
if (current > max) {
return;
}
}
this.currentValue = newValue;
},
inputDot() {
if (this.currentValue.indexOf('.') >= 0) {
return;
}
if (!this.previousValue && this.currentSymbol === '') {
this.currentValue = '-' + this.currentValue;
this.currentSymbol = '';
}
if (this.currentValue.length < 1) {
this.currentValue = '0';
} else if (this.currentValue === '-') {
this.currentValue = '-0';
}
this.currentValue = this.currentValue + '.';
},
setSymbol(symbol) {
if (this.currentValue) {
if (this.currentSymbol) {
const lastFormulaCalcResult = this.confirm();
if (!lastFormulaCalcResult) {
return;
}
}
this.previousValue = this.currentValue;
this.currentValue = '';
}
this.currentSymbol = symbol;
},
backspace() {
if (!this.currentValue || this.currentValue.length < 1) {
if (this.currentSymbol) {
this.currentValue = this.previousValue;
this.previousValue = '';
this.currentSymbol = '';
}
return;
}
this.currentValue = this.currentValue.substring(0, this.currentValue.length - 1);
},
clear() {
this.currentValue = '';
this.previousValue = '';
this.currentSymbol = '';
},
confirm() {
if (this.currentSymbol && this.currentValue.length >= 1) {
const previousValue = stringCurrencyToNumeric(this.previousValue);
const currentValue = stringCurrencyToNumeric(this.currentValue);
let finalValue = 0;
switch (this.currentSymbol) {
case '+':
finalValue = previousValue + currentValue;
break;
case '':
finalValue = previousValue - currentValue;
break;
case '×':
finalValue = Math.round(previousValue * currentValue / 100);
break;
default:
finalValue = previousValue;
}
if (isString(this.minValue) && this.minValue !== '') {
const min = stringCurrencyToNumeric(this.minValue);
if (finalValue < min) {
this.$toast('Numeric Overflow');
return false;
}
}
if (isString(this.maxValue) && this.maxValue !== '') {
const max = stringCurrencyToNumeric(this.maxValue);
if (finalValue > max) {
this.$toast('Numeric Overflow');
return false;
}
}
this.currentValue = this.getStringValue(finalValue);
this.previousValue = '';
this.currentSymbol = '';
return true;
} else if (this.currentSymbol && this.currentValue.length < 1) {
this.currentValue = this.previousValue;
this.previousValue = '';
this.currentSymbol = '';
return true;
} else {
const value = stringCurrencyToNumeric(this.currentValue);
this.$emit('update:modelValue', value);
this.close();
return true;
}
},
close() {
this.$emit('update:show', false);
},
onSheetOpen() {
this.currentValue = this.getStringValue(this.modelValue);
},
onSheetClosed() {
this.close();
}
}
}
</script>
<style>
.numpad-sheet {
height: auto;
}
.numpad-values {
border-bottom: 1px solid var(--f7-page-bg-color);
}
.numpad-value {
display: flex;
position: relative;
padding-left: 16px;
line-height: 1;
height: var(--ebk-numpad-value-height);
align-items: center;
box-sizing: border-box;
user-select: none;
}
.numpad-value-small {
font-size: var(--ebk-numpad-value-small-font-size);
}
.numpad-value-normal {
font-size: var(--ebk-numpad-value-normal-font-size);
}
.numpad-value-large {
font-size: var(--ebk-numpad-value-large-font-size);
}
.numpad-buttons {
display: flex;
flex-wrap: wrap;
}
.numpad-button {
display: flex;
position: relative;
text-align: center;
border-radius: 0;
border-right: 1px solid var(--f7-page-bg-color);
border-bottom: 1px solid var(--f7-page-bg-color);
height: 60px;
flex-direction: column;
justify-content: center;
align-items: center;
box-sizing: border-box;
user-select: none;
touch-action: none;
}
.numpad-button-num {
width: calc(80% / 3);
}
.numpad-button-function, .numpad-button-confirm {
width: 20%;
}
.numpad-button-num.active-state, .numpad-button-function.active-state {
background-color: rgba(var(--f7-color-black-rgb), .15);
}
.numpad-button-text {
display: block;
font-size: var(--ebk-numpad-normal-button-font-size);
font-weight: normal;
line-height: 1;
}
.numpad-button-text-normal {
color: var(--f7-color-black);
}
.dark .numpad-button-text-normal {
color: var(--f7-color-white);
}
.numpad-button-text-confirm {
font-size: var(--ebk-numpad-confirm-button-font-size);
}
</style>