This commit is contained in:
Andrey Cunha
2026-03-12 23:05:52 -03:00
parent 40db0af098
commit 7113b026ef
33 changed files with 7939 additions and 2225 deletions
@@ -0,0 +1,19 @@
application.type=widget
application.code=portalfornecedor
application.title=portalfornecedor
application.description=portalfornecedor
application.fluig.version=null
application.category=SYSTEM
application.renderer=freemarker
developer.code=DESKTOP-0E2LAA6
developer.name=Home
developer.url=http://www.fluig.com
application.uiwidget=true
application.mobileapp=false
application.version=${build.version}-${build.revision}
view.file=view.ftl
edit.file=edit.ftl
locale.file.base.name=portalfornecedor
application.resource.js.1=/resources/js/portalfornecedor.js
application.resource.css.2=/resources/css/portalfornecedor.css
hash=4a16315e9e66fa7d797b3f6b1fb365b69f9a4ce2
@@ -0,0 +1,5 @@
<div id="MyWidget_${instanceId}" class="super-widget wcm-widget-class fluig-style-guide" data-params="window.MyWidget && MyWidget.instance ? MyWidget.instance() : {}">
</div>
@@ -0,0 +1,184 @@
<div id="MyWidget_${instanceId}" class="super-widget wcm-widget-class fluig-style-guide"
data-params="MyWidget.instance()">
<link rel="stylesheet" href="/style-guide/css/fluig-style-guide.min.css">
<div class="page-wrapper portal-shell">
<div class="page-header">
<div class="page-eyebrow">Portal Fornecedor</div>
<h2 class="page-title">
<i class="flaticon flaticon-account-box"></i>
Portal de Envio de Documentos
</h2>
<p class="page-subtitle">Informe os dados da nota fiscal para comprovação no sistema.</p>
</div>
<div class="form-card">
<h4 class="titulo-secao">Dados do documento</h4>
<p class="sub-secao">Preencha os campos obrigatórios para iniciar a solicitação.</p>
<div class="row">
<div class="form-group col-md-3">
<label>Data</label>
<input type="text" name="data_abertura" id="data_abertura" class="form-control" readonly>
</div>
<div class="form-group col-md-3 divEmitidoPor alertaCampo">
<label>Emitido por <strong class="text-danger">*</strong></label>
<select name="emitido_por" id="emitido_por" class="form-control">
<option value="">Selecionar emissor</option>
<option value="fornecedor">Fornecedor</option>
<option value="colaborador">Colaborador</option>
</select>
</div>
<div class="form-group col-md-3 divEntidadeResponsavel alertaCampo">
<label>Responsavel pela emissão <strong class="text-danger">*</strong></label>
<input type="text" class="form-control"
name="entidade_responsavel"
id="entidade_responsavel"
placeholder="Empresa ou colaborador">
</div>
<div class="form-group col-md-3">
<label>E-mail do solicitante</label>
<input type="email"
name="emailSolicitante"
id="emailSolicitante"
class="form-control"
placeholder="email@empresa.com">
</div>
</div>
<div class="row">
<div class="form-group col-md-3 divTipoCadastro alertaCampo">
<label>Tipo de cadastro <strong class="text-danger">*</strong></label>
<select name="tipo_cadastro" id="tipo_cadastro" class="form-control">
<option value="">Selecionar</option>
<option value="cpf">CPF</option>
<option value="cnpj">CNPJ</option>
</select>
</div>
<div class="form-group col-md-3 divCnpj alertaCampo">
<label>CNPJ <strong class="text-danger">*</strong></label>
<input type="text"
name="cnpj"
id="cnpj"
class="form-control"
placeholder="00.000.000/0000-00"
mask="00.000.000/0000-00">
</div>
<div class="form-group col-md-3 divCpf alertaCampo" style="display:none;">
<label>CPF <strong class="text-danger">*</strong></label>
<input type="text"
name="cpf"
id="cpf"
class="form-control"
placeholder="000.000.000-00"
mask="000.000.000-00">
</div>
<div class="form-group col-md-3">
<label>Tipo de documento</label>
<select name="tipo_documento" id="tipo_documento" class="form-control">
<option value="">Selecionar</option>
<option value="danfe">Nota Fiscal Mercadoria</option>
<option value="nota_fiscal_servico">Nota Fiscal Servico</option>
</select>
</div>
</div>
<div class="row">
<div class="form-group col-md-6 alertaCampo">
<label>Numero do documento <strong class="text-danger">*</strong></label>
<input type="text"
name="numero_documento"
id="numero_documento"
class="form-control"
placeholder="Numero da nota">
</div>
<div class="form-group col-md-6">
<label>Valor do documento</label>
<div class="input-group">
<span class="input-group-addon">R$</span>
<input type="text"
name="valor"
id="valor"
class="form-control"
mask="#000.000.000,00"
placeholder="0,00">
</div>
</div>
</div>
<div class="row">
<div class="form-group col-md-12">
<label>Anexar documento <strong class="text-danger">*</strong></label>
<p class="text-muted">
Utilize o botão abaixo para anexar o documento.
</p>
<button type="button" class="btn btn-primary btn-anexo" id="anexaDocumento">
<i class="flaticon flaticon-paperclip"></i>
Anexar documento
</button>
<input type="file" id="arquivoLocal" style="display:none">
<div id="arquivoLocalNome" class="arquivo-nome"></div>
</div>
</div>
</div>
<div class="form-card">
<h4 class="titulo-secao">Descrição dos serviços</h4>
<p class="sub-secao">Inclua detalhes para facilitar a análise.</p>
<textarea class="form-control"
rows="4"
id="justificativa"
name="justificativa"
placeholder="Descreva os serviços prestados"></textarea>
</div>
<div id="envioStatus" class="envio-status hidden"></div>
<div class="text-center">
<button type="button" id="btnEnviarNota" class="btn btn-enviar btn-lg">
Enviar documento
</button>
</div>
</div>
</div>
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>
<context-root>/portalfornecedor</context-root>
<disable-cross-context>false</disable-cross-context>
</jboss-web>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
</web-app>
@@ -0,0 +1,346 @@
.wcm-widget-class {
background:
radial-gradient(circle at 2px 2px, rgba(13, 109, 141, 0.06) 1px, transparent 0) 0 0 / 18px 18px,
linear-gradient(180deg, #f8fbfd 0%, #eef3f7 100%);
}
.portal-shell {
--pf-bg: #f2f5f8;
--pf-card: #ffffff;
--pf-border: #d9e2ec;
--pf-ink: #133045;
--pf-muted: #5f7282;
--pf-primary: #0a6d8d;
--pf-primary-strong: #085a74;
--pf-success: #0f766e;
--pf-success-bg: #ecfdf5;
--pf-danger: #b42318;
max-width: 980px;
margin: 28px auto;
padding: 0 12px 32px;
color: var(--pf-ink);
}
.page-header {
position: relative;
margin: 0 0 20px;
padding: 18px 16px 14px;
border: 1px solid #0b4a5f;
border-radius: 12px;
background: #0b556b;
box-shadow: 0 8px 20px rgba(11, 85, 107, 0.24);
}
.page-header::before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 180px;
height: 4px;
border-radius: 99px;
background: rgba(255, 255, 255, 0.75);
}
.page-brand {
position: absolute;
right: 0;
top: 6px;
width: 188px;
height: 64px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 0;
border: none;
background: transparent;
box-shadow: none;
padding: 0;
}
.page-brand img {
max-width: 94%;
max-height: 82%;
object-fit: contain;
}
.brand-fallback-text {
display: none;
font-size: 14px;
font-weight: 700;
color: #ffffff;
}
.page-brand.brand-fallback .brand-fallback-text {
display: inline-block;
}
.page-eyebrow {
display: inline-block;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
color: #d7f0f7;
margin-bottom: 6px;
}
.page-title {
margin: 0;
font-size: 34px;
line-height: 1.15;
font-weight: 800;
color: #ffffff;
}
.page-title i {
margin-right: 8px;
color: #d7f0f7;
}
.page-subtitle {
margin: 8px 0 0;
color: #d5e8ef;
font-size: 15px;
max-width: 70%;
}
.form-card {
background: var(--pf-card);
border: 1px solid var(--pf-border);
border-radius: 14px;
padding: 22px 20px 16px;
margin-bottom: 16px;
box-shadow: 0 8px 24px rgba(16, 24, 40, 0.06);
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.portal-shell .page-header .page-title,
.portal-shell .page-header .page-title i {
color: #ffffff !important;
}
.portal-shell .page-header .page-subtitle {
color: #e6f2f6 !important;
}
.portal-shell .page-header .page-eyebrow {
color: #dff6ff !important;
}
.portal-shell .form-card {
background: #ffffff !important;
border-color: #cfdce8 !important;
}
.portal-shell .arquivo-nome:empty {
display: none;
}
.form-card:hover {
transform: translateY(-2px);
box-shadow: 0 12px 30px rgba(16, 24, 40, 0.08);
}
.titulo-secao {
margin: 0;
font-size: 22px;
line-height: 1.2;
font-weight: 800;
color: #0b3f55;
}
.sub-secao {
margin: 6px 0 18px;
color: var(--pf-muted);
font-size: 13px;
}
.form-group {
margin-bottom: 16px;
}
.form-group > label {
display: block;
margin-bottom: 6px;
font-size: 13px;
font-weight: 700;
color: #324b5d;
}
.portal-shell .form-control,
.portal-shell .input-group-addon,
.portal-shell select.form-control {
border-radius: 8px;
}
.portal-shell .form-control {
height: 40px;
border: 1px solid #c9d5e2;
transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.portal-shell textarea.form-control {
min-height: 120px;
resize: vertical;
}
.portal-shell .form-control:hover {
border-color: #8fb5c3;
}
.portal-shell .form-control:focus {
border-color: #0a6d8d;
box-shadow: 0 0 0 3px rgba(10, 109, 141, 0.12);
}
.portal-shell .has-error .form-control,
.portal-shell .alertaCampo.has-error .form-control {
border-color: var(--pf-danger);
}
.btn-anexo {
background: #eef4f7;
border: 1px dashed #9db7c5;
color: #133045;
border-radius: 8px;
padding: 10px 14px;
font-weight: 700;
transition: background 0.15s ease;
}
.btn-anexo:hover {
background: #e4eef3;
}
.arquivo-nome {
margin-top: 10px;
padding: 8px 10px;
border-radius: 8px;
background: #f4f8fb;
border: 1px solid #d7e5ef;
color: #365266;
font-size: 13px;
}
.btn-enviar {
margin-top: 10px;
min-width: 220px;
border-radius: 10px;
background: linear-gradient(135deg, #0a6d8d 0%, #0f8f98 100%);
border: none;
padding: 12px 28px;
font-size: 16px;
font-weight: 700;
color: white;
transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.btn-enviar:hover {
transform: translateY(-1px);
box-shadow: 0 10px 22px rgba(10, 109, 141, 0.25);
}
.envio-status {
margin: 0 0 14px;
padding: 12px 14px;
border-radius: 10px;
border: 1px solid transparent;
font-size: 14px;
font-weight: 600;
}
.envio-status.hidden {
display: none;
}
.envio-status.success {
color: #065f46;
background: var(--pf-success-bg);
border-color: #a7f3d0;
}
.envio-status.error {
color: #7a271a;
background: #fef3f2;
border-color: #fecdca;
}
.portal-success-state {
max-width: 760px;
margin: 32px auto;
padding: 26px 24px;
border: 1px solid #b7ebd8;
border-radius: 12px;
background: linear-gradient(180deg, #f4fffb 0%, #ecfdf5 100%);
animation: fadeIn 0.4s ease;
}
.portal-success-title {
margin: 0 0 8px;
color: #0f5132;
font-weight: 800;
}
.portal-success-desc {
margin: 0;
color: #1f5f46;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@media (max-width: 991px) {
.portal-shell {
padding: 0 10px 24px;
}
.page-title {
font-size: 28px;
}
.page-subtitle {
max-width: 100%;
padding-right: 184px;
}
}
@media (max-width: 767px) {
.page-title {
font-size: 24px;
}
.page-header {
padding-top: 76px;
}
.page-brand {
left: 0;
right: auto;
top: 8px;
width: 164px;
height: 58px;
}
.page-subtitle {
padding-right: 0;
}
.form-card {
padding: 16px 14px 10px;
border-radius: 12px;
}
.btn-enviar {
width: 100%;
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

@@ -0,0 +1,460 @@
if (typeof window !== "undefined") {
window.WCMAPI = window.WCMAPI || {};
if (typeof window.WCMAPI.isMobileAppMode !== "function") {
window.WCMAPI.isMobileAppMode = function () { return false; };
}
}
function showCamera(param) {
if (typeof JSInterface !== "undefined" && JSInterface && typeof JSInterface.showCamera === "function") {
JSInterface.showCamera(param);
return true;
}
return false;
}
var MyWidget = SuperWidget.extend({
init: function () {
this.root = $("#MyWidget_" + this.instanceId);
this.anexoInfo = null;
this.gedParentFolderId = 10;
this.isSending = false;
this.bindEvents();
this.setupInitialValues();
},
bindEvents: function () {
var self = this;
this.root.find("#btnEnviarNota_" + this.instanceId + ", #btnEnviarNota").off("click").on("click", function () {
self.enviarDocumento();
});
this.root.find("#anexaDocumento").off("click").on("click", function () {
self.handleAnexo();
});
this.root.find("#arquivoLocal").off("change").on("change", function () {
self.onArquivoSelecionado(this);
});
this.root.find("#tipo_cadastro").off("change").on("change", function () {
self.toggleTipoCadastro(this.value);
self.clearFieldError("#cpf");
self.clearFieldError("#cnpj");
});
this.root.find("#cpf").off("input").on("input", function () {
this.value = self.mascaraCPF(this.value);
});
this.root.find("#cnpj").off("input").on("input", function () {
this.value = self.mascaraCNPJ(this.value);
});
},
setupInitialValues: function () {
this.root.find("#data_abertura").val(this.getCurrentDate());
this.root.find("#tipo_cadastro").val("cpf").trigger("change");
this.root.find("#emitido_por").val("fornecedor");
this.root.find("#tipo_documento").val("danfe");
this.clearStatus();
},
onArquivoSelecionado: function (inputEl) {
var file = inputEl && inputEl.files && inputEl.files[0] ? inputEl.files[0] : null;
if (!file) {
this.anexoInfo = null;
this.root.find("#arquivoLocalNome").text("");
return;
}
this.anexoInfo = {
fileName: file.name,
mimeType: file.type || "application/octet-stream",
fileSize: file.size || 0,
file: file
};
this.root.find("#arquivoLocalNome").text("Arquivo selecionado: " + file.name + " (" + this.formatFileSize(file.size || 0) + ")");
this.clearStatus();
console.log("[portalfornecedor] anexo preparado para envio:", {
fileName: this.anexoInfo.fileName,
mimeType: this.anexoInfo.mimeType,
fileSize: this.anexoInfo.fileSize
});
},
handleAnexo: function () {
if (showCamera("anexo_documento")) {
return;
}
if (this.openAttachmentTab()) {
return;
}
this.root.find("#arquivoLocal").trigger("click");
},
openAttachmentTab: function () {
try {
var parentDoc = window.parent && window.parent.document ? window.parent.document : document;
var selectors = [
"#tab-attachments",
"a[href*='attachments']",
"a[aria-controls*='attachments']",
"[data-tab*='attachments']"
];
for (var i = 0; i < selectors.length; i++) {
var el = parentDoc.querySelector(selectors[i]);
if (el) {
el.click();
return true;
}
}
} catch (e) {
// ignore
}
return false;
},
toggleTipoCadastro: function (tipo) {
tipo = this.normalizeTipoCadastro(tipo);
var divCpf = this.root.find(".divCpf");
var divCnpj = this.root.find(".divCnpj");
var cpf = this.root.find("#cpf");
var cnpj = this.root.find("#cnpj");
if (tipo === "cpf") {
divCpf.show();
divCnpj.hide();
cpf.prop("readonly", false);
cnpj.prop("readonly", true).val("");
return;
}
if (tipo === "cnpj") {
divCpf.hide();
divCnpj.show();
cnpj.prop("readonly", false);
cpf.prop("readonly", true).val("");
return;
}
divCpf.hide();
divCnpj.show();
cpf.prop("readonly", true).val("");
cnpj.prop("readonly", true).val("");
},
enviarDocumento: function () {
var self = this;
if (this.isSending) {
return;
}
if (!this.validateRequiredFields()) {
this.setStatus("error", "Revise os campos obrigatorios destacados para continuar.");
FLUIGC.toast({
title: "Aviso",
message: "Preencha os campos obrigatorios antes de enviar.",
type: "warning"
});
return;
}
if (!this.anexoInfo || !this.anexoInfo.file) {
this.setStatus("error", "Selecione um anexo antes de enviar o documento.");
FLUIGC.toast({
title: "Aviso",
message: "Selecione um anexo antes de enviar o documento.",
type: "warning"
});
return;
}
var tipoCadastro = this.normalizeTipoCadastro(this.value("#tipo_cadastro"));
var cpf = this.onlyDigits(this.value("#cpf"));
var cnpj = this.onlyDigits(this.value("#cnpj"));
var numeroDocumento = this.value("#numero_documento");
var valor = this.normalizeMoney(this.value("#valor"));
var documentoPessoa = tipoCadastro === "cpf" ? cpf : cnpj;
var cpfField = tipoCadastro === "cpf" ? cpf : "";
this.setLoading(true, "Enviando documento, aguarde...");
this.uploadAnexoToECM(this.anexoInfo.file)
.done(function (docData) {
var payloadProcesso = {
targetState: 0,
subProcessTargetState: 0,
comment: "Solicitacao criada via widget",
formFields: {
data_abertura: self.value("#data_abertura"),
emitido_por: self.value("#emitido_por"),
entidade_responsavel: self.value("#entidade_responsavel"),
tipo_cadastro: tipoCadastro,
emailSolicitante: self.value("#emailSolicitante"),
cpf: cpfField || documentoPessoa,
tipo_documento: self.value("#tipo_documento"),
numero_documento: numeroDocumento,
valor: valor,
justificativa: self.value("#justificativa"),
anexo_documento_id: String(docData.documentId || ""),
anexo_documento_nome: self.anexoInfo.fileName,
anexo_documento_mime: self.anexoInfo.mimeType
}
};
window.__portalfornecedor_lastProcessPayload = payloadProcesso;
console.log("[portalfornecedor] payload direto processo:", payloadProcesso);
self.enviarDiretoProcesso(payloadProcesso)
.done(function (response) {
console.log("[portalfornecedor] response processo direto:", response);
self.setLoading(false);
self.renderSuccessState(response);
})
.fail(function (xhrDireto) {
self.setLoading(false);
console.warn("[portalfornecedor] falha no envio direto:", xhrDireto);
console.error("[portalfornecedor] detalhe erro processo direto:", {
status: xhrDireto.status,
statusText: xhrDireto.statusText,
responseText: xhrDireto.responseText
});
self.setStatus("error", "Falha ao iniciar processo. Veja o console para detalhes.");
FLUIGC.toast({
title: "Erro",
message: "Falha ao iniciar processo. Veja o console para detalhes.",
type: "danger"
});
});
})
.fail(function (uploadErr) {
self.setLoading(false);
console.error("[portalfornecedor] falha upload documento ECM:", uploadErr);
self.setStatus("error", "Falha ao enviar anexo para o GED.");
FLUIGC.toast({
title: "Erro",
message: "Falha ao enviar anexo para o GED.",
type: "danger"
});
});
},
renderSuccessState: function (response) {
var processInstanceId = this.extractProcessInstanceId(response);
var idText = processInstanceId ? ("Solicitação " + processInstanceId) : "Solicitação";
var html = ""
+ "<div class='portal-success-state'>"
+ " <h3 class='portal-success-title'>" + idText + " enviada com sucesso.</h3>"
+ " <p class='portal-success-desc'>Sua Solicitação foi encaminhada para o Grupo Ginseng para análise.</p>"
+ "</div>";
this.root.html(html);
console.log("[portalfornecedor] success state renderizado.");
},
extractProcessInstanceId: function (response) {
if (!response) return "";
if (response.processInstanceId) return response.processInstanceId;
if (response.content && response.content.processInstanceId) return response.content.processInstanceId;
if (response.content && response.content.processInstanceid) return response.content.processInstanceid;
if (response.content && response.content.requestNumber) return response.content.requestNumber;
return "";
},
enviarDiretoProcesso: function (payloadProcesso) {
return $.ajax({
url: "/process-management/api/v2/processes/FlowEssentials_LancamentodeDocumento/start",
type: "POST",
contentType: "application/json",
data: JSON.stringify(payloadProcesso)
});
},
uploadAnexoToECM: function (file) {
var self = this;
var dfd = $.Deferred();
var fileName = file.name;
var uploadUrl = "/api/public/2.0/contentfiles/upload/?fileName=" + encodeURIComponent(fileName);
fetch(uploadUrl, {
method: "POST",
headers: {
"Content-Type": "application/octet-stream"
},
body: file
})
.then(function (resp) {
if (!resp.ok) throw new Error("Falha no upload binario");
return resp.text();
})
.then(function () {
var companyId = (window.WCMAPI && WCMAPI.organizationId) ? String(WCMAPI.organizationId) : "1";
var createPayload = {
companyId: companyId,
description: fileName,
parentId: self.gedParentFolderId,
immutable: true,
isPrivate: false,
downloadEnabled: true,
attachments: [{ fileName: fileName }]
};
return fetch("/api/public/ecm/document/createDocument", {
method: "POST",
headers: {
"Content-Type": "application/json;charset=utf-8"
},
body: JSON.stringify(createPayload)
});
})
.then(function (resp) {
if (!resp.ok) throw new Error("Falha ao criar documento no GED");
return resp.json();
})
.then(function (data) {
var content = data && data.content ? data.content : {};
var documentId = content.id || content.documentId;
if (!documentId) throw new Error("GED nao retornou documentId");
dfd.resolve({ documentId: documentId, raw: data });
})
.catch(function (err) {
dfd.reject(err);
});
return dfd.promise();
},
setLoading: function (isLoading, message) {
this.isSending = !!isLoading;
var btn = this.root.find("#btnEnviarNota");
if (isLoading) {
btn.prop("disabled", true).text("Enviando...");
this.setStatus("success", message || "Processando...");
return;
}
btn.prop("disabled", false).text("Enviar documento");
},
setStatus: function (type, message) {
var box = this.root.find("#envioStatus");
if (!box.length) return;
box.removeClass("hidden success error");
box.addClass(type === "error" ? "error" : "success");
box.text(message || "");
},
clearStatus: function () {
var box = this.root.find("#envioStatus");
if (!box.length) return;
box.removeClass("success error").addClass("hidden").text("");
},
validateRequiredFields: function () {
var ok = true;
var tipoCadastro = this.normalizeTipoCadastro(this.value("#tipo_cadastro"));
if (!this.value("#emitido_por")) ok = this.markRequired("#emitido_por") && ok;
if (!this.value("#entidade_responsavel")) ok = this.markRequired("#entidade_responsavel") && ok;
if (!this.value("#tipo_cadastro")) ok = this.markRequired("#tipo_cadastro") && ok;
if (!this.value("#numero_documento")) ok = this.markRequired("#numero_documento") && ok;
if (!this.value("#justificativa")) ok = this.markRequired("#justificativa") && ok;
if (tipoCadastro === "cpf") {
if (!this.onlyDigits(this.value("#cpf"))) ok = this.markRequired("#cpf") && ok;
this.clearFieldError("#cnpj");
} else if (tipoCadastro === "cnpj") {
if (!this.onlyDigits(this.value("#cnpj"))) ok = this.markRequired("#cnpj") && ok;
this.clearFieldError("#cpf");
}
return ok;
},
markRequired: function (selector) {
var input = this.root.find(selector);
if (!input.length) return false;
var container = input.closest(".alertaCampo, .form-group");
if (container.length) container.addClass("has-error");
input.one("input change", function () {
if ($.trim($(this).val())) {
$(this).closest(".alertaCampo, .form-group").removeClass("has-error");
}
});
return false;
},
clearFieldError: function (selector) {
var input = this.root.find(selector);
if (!input.length) return;
input.closest(".alertaCampo, .form-group").removeClass("has-error");
},
value: function (selector) {
return (this.root.find(selector).val() || "").toString().trim();
},
getCurrentDate: function () {
var now = new Date();
var yyyy = now.getFullYear();
var mm = ("0" + (now.getMonth() + 1)).slice(-2);
var dd = ("0" + now.getDate()).slice(-2);
return yyyy + "-" + mm + "-" + dd;
},
mascaraCPF: function (value) {
var v = (value || "").replace(/\D/g, "").slice(0, 11);
v = v.replace(/(\d{3})(\d)/, "$1.$2");
v = v.replace(/(\d{3})(\d)/, "$1.$2");
v = v.replace(/(\d{3})(\d{1,2})$/, "$1-$2");
return v;
},
mascaraCNPJ: function (value) {
var v = (value || "").replace(/\D/g, "").slice(0, 14);
v = v.replace(/^(\d{2})(\d)/, "$1.$2");
v = v.replace(/^(\d{2})\.(\d{3})(\d)/, "$1.$2.$3");
v = v.replace(/\.(\d{3})(\d)/, ".$1/$2");
v = v.replace(/(\d{4})(\d)/, "$1-$2");
return v;
},
onlyDigits: function (value) {
return (value || "").replace(/\D/g, "");
},
normalizeMoney: function (value) {
var raw = (value || "").toString().trim();
if (!raw) return "0,00";
if (raw.indexOf(",") >= 0) return raw;
if (raw.indexOf(".") >= 0) return raw.replace(".", ",");
return raw + ",00";
},
normalizeTipoCadastro: function (value) {
return (value || "").toString().trim().toLowerCase();
},
formatFileSize: function (bytes) {
var b = Number(bytes || 0);
if (b <= 0) return "0 KB";
if (b < 1024) return b + " B";
if (b < 1048576) return (b / 1024).toFixed(1) + " KB";
return (b / 1048576).toFixed(2) + " MB";
}
});