Atualização floresta
This commit is contained in:
parent
0886fd5c3e
commit
2d4d8f8929
103 changed files with 19266 additions and 14160 deletions
|
|
@ -27,126 +27,19 @@
|
|||
<script lang="ts">
|
||||
import { computed, defineComponent, type PropType, ref, watch } from "vue"
|
||||
import type { PadroesEntradas } from "./tiposEntradas"
|
||||
import "./EliEntradaNumero.css"
|
||||
import {
|
||||
casasDecimaisFromPrecisao,
|
||||
formatarNumero,
|
||||
limitarCasasDecimais,
|
||||
parseNumero,
|
||||
somenteNumeros,
|
||||
somenteNumerosESeparadorDecimal,
|
||||
valorParcialDecimal,
|
||||
} from "./EliEntradaNumero.helpers"
|
||||
|
||||
type EntradaNumero = PadroesEntradas["numero"]
|
||||
|
||||
function casasDecimaisFromPrecisao(precisao: number): number {
|
||||
if (!Number.isFinite(precisao) || precisao <= 0) return 0
|
||||
if (precisao >= 1) return 0
|
||||
|
||||
// Preferência por contar casas decimais na representação (ex.: 0.01 -> 2)
|
||||
const texto = precisao.toString()
|
||||
if (texto.includes("e-")) {
|
||||
const [, exp] = texto.split("e-")
|
||||
const n = Number(exp)
|
||||
return Number.isFinite(n) ? n : 0
|
||||
}
|
||||
const idx = texto.indexOf(".")
|
||||
if (idx === -1) return 0
|
||||
const dec = texto.slice(idx + 1).replace(/0+$/, "")
|
||||
return dec.length
|
||||
}
|
||||
|
||||
/**
|
||||
* Analisa a entrada de texto e converte em um valor numérico válido (float).
|
||||
* Troca a vírgula brasileira por ponto antes de passar para o parser nativo.
|
||||
*
|
||||
* @param texto - O texto bruto digitado ou vindo do estado
|
||||
* @returns O número processado ou `null` caso inválido ou vazio
|
||||
*/
|
||||
function parseNumero(texto: string): number | null {
|
||||
const normalizado = (texto ?? "").trim().replace(/,/g, ".")
|
||||
if (!normalizado) return null
|
||||
const n = Number(normalizado)
|
||||
if (Number.isNaN(n)) return null
|
||||
return n
|
||||
}
|
||||
|
||||
/**
|
||||
* Formata um valor numérico para a exibição na interface (usando vírgula como separador).
|
||||
* Em caso de precisão nula (modo livre), preserva a semântica de exibição direta sem forçar o preenchimento de zeros (toFixed).
|
||||
*
|
||||
* @param value - O valor numérico de fato emitido
|
||||
* @param casas - Opcionalmente, o número exato de casas decimais para fixar
|
||||
* @returns String formatada amigável para exibição em pt-BR
|
||||
*/
|
||||
function formatarNumero(
|
||||
value: number | null | undefined,
|
||||
casas: number | null,
|
||||
) {
|
||||
if (value === null || value === undefined) return ""
|
||||
if (casas === null) return String(value).replace(/\./g, ",")
|
||||
|
||||
// Garantimos que o texto visual corresponda ao value (fixed).
|
||||
const fixed = Number(value).toFixed(Math.max(0, casas))
|
||||
// Exibe com vírgula (pt-BR)
|
||||
return fixed.replace(/\./g, ",")
|
||||
}
|
||||
|
||||
/**
|
||||
* Retira todo tipo de sujeira de uma string, devolvendo restritamente números (para inteiros).
|
||||
*
|
||||
* @param texto - String de entrada
|
||||
* @returns Apenas dígitos de 0 a 9
|
||||
*/
|
||||
function somenteNumeros(texto: string) {
|
||||
return (texto ?? "").replace(/\D+/g, "")
|
||||
}
|
||||
|
||||
/**
|
||||
* Higieniza o texto preservando apenas os dígitos e exatamente UM separador decimal.
|
||||
* Colapsa múltiplos separadores e normaliza se o separador vier no início (",4" => "0,4").
|
||||
*
|
||||
* @param texto - Texto misto de entrada
|
||||
* @returns String contendo número e (opcionalmente) uma vírgula ou ponto residual
|
||||
*/
|
||||
function somenteNumerosESeparadorDecimal(texto: string) {
|
||||
// Mantém apenas números e UM separador decimal ("," ou "."), sem sinais.
|
||||
// Implementação baseada em regex + colapso de separadores.
|
||||
const limpo = (texto ?? "").replace(/[^0-9.,]+/g, "")
|
||||
const matchSep = limpo.match(/[.,]/)
|
||||
if (!matchSep) return limpo
|
||||
|
||||
const sep = matchSep[0]
|
||||
const idx = limpo.indexOf(sep)
|
||||
const antesRaw = limpo.slice(0, idx).replace(/[.,]/g, "")
|
||||
const depois = limpo.slice(idx + 1).replace(/[.,]/g, "")
|
||||
|
||||
// Se o usuário começa pelo separador (",4"), normalizamos para "0,4".
|
||||
const antes = antesRaw.length ? antesRaw : "0"
|
||||
return `${antes}${sep}${depois}`
|
||||
}
|
||||
|
||||
function limitarCasasDecimais(texto: string, casas: number | null) {
|
||||
if (casas === null) return texto
|
||||
if (casas <= 0) return texto.replace(/[.,]/g, "")
|
||||
|
||||
const matchSep = texto.match(/[.,]/)
|
||||
if (!matchSep) return texto
|
||||
const sep = matchSep[0]
|
||||
const idx = texto.indexOf(sep)
|
||||
|
||||
const inteiro = texto.slice(0, idx)
|
||||
const frac = texto.slice(idx + 1)
|
||||
return `${inteiro}${sep}${frac.slice(0, casas)}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve o edge-case de digitação transitória parcial terminada em separador (ex: "1,").
|
||||
* Identifica se a string tem este formato pendente e retorna temporariamente sua base inteira
|
||||
* sem permitir que o valor se torne nulo.
|
||||
*
|
||||
* @param texto - O texto já higienizado, tipicamente terminando em vírgula ou ponto
|
||||
* @returns A conversão parcial estrita ou `null` caso falhe
|
||||
*/
|
||||
function valorParcialDecimal(texto: string): number | null {
|
||||
// Regra (B): se o usuário digitou "1," ou "1." emite 1.
|
||||
const m = texto.match(/^(\d+)[.,]$/)
|
||||
if (!m) return null
|
||||
const n = Number(m[1])
|
||||
return Number.isNaN(n) ? null : n
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
name: "EliEntradaNumero",
|
||||
inheritAttrs: false,
|
||||
|
|
@ -229,12 +122,8 @@ export default defineComponent({
|
|||
}
|
||||
|
||||
// Modo livre (sem precisao) ou inteiro: aceita números e 1 separador (no caso livre)
|
||||
const base = isInteiro.value
|
||||
? somenteNumeros(texto)
|
||||
: somenteNumerosESeparadorDecimal(texto)
|
||||
const textoFiltrado = isInteiro.value
|
||||
? base
|
||||
: limitarCasasDecimais(base, casasDecimais.value)
|
||||
const base = isInteiro.value ? somenteNumeros(texto) : somenteNumerosESeparadorDecimal(texto)
|
||||
const textoFiltrado = isInteiro.value ? base : limitarCasasDecimais(base, casasDecimais.value)
|
||||
|
||||
// Emissão:
|
||||
// - vazio => null
|
||||
|
|
@ -242,9 +131,7 @@ export default defineComponent({
|
|||
// - caso geral => parse normal
|
||||
let out: EntradaNumero["value"] = null
|
||||
if (textoFiltrado) {
|
||||
const parcial = isInteiro.value
|
||||
? null
|
||||
: valorParcialDecimal(textoFiltrado)
|
||||
const parcial = isInteiro.value ? null : valorParcialDecimal(textoFiltrado)
|
||||
const n = parcial ?? parseNumero(textoFiltrado)
|
||||
out = (n === null ? null : n) as EntradaNumero["value"]
|
||||
}
|
||||
|
|
@ -269,19 +156,3 @@ export default defineComponent({
|
|||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.eli-entrada__prefixo,
|
||||
.eli-entrada__sufixo {
|
||||
opacity: 0.75;
|
||||
font-size: 0.9em;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.eli-entrada__prefixo {
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.eli-entrada__sufixo {
|
||||
margin-left: 6px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue