596 lines
23 KiB
PHP
596 lines
23 KiB
PHP
<style>
|
|
/* Sembunyikan semua dulu saat pertama kali load */
|
|
.official-section,
|
|
.unofficial-section {
|
|
display: none;
|
|
}
|
|
</style>
|
|
<!-- Main content -->
|
|
<section class="content" style="zoom: 90%;">
|
|
<div class="container-fluid">
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<div class="row">
|
|
<div class="col-sm-6">
|
|
<h3 class="card-title">Pesan Siaran</h3>
|
|
</div>
|
|
<div class="col-sm-6">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-4">
|
|
<div class="card-body">
|
|
<form method="post" enctype="multipart/form-data">
|
|
<div class="form-group">
|
|
<label>Tipe WhatsApp Gateway</label>
|
|
<select class="form-control" name="gateway_type" id="gateway_type" required>
|
|
<option value="unofficial">Unofficial WA API</option>
|
|
<option value="official">Official WA API</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Data Server</label>
|
|
<div class="select2-primary">
|
|
<select class="select2" name="ids[]" multiple="multiple" data-placeholder="Select a State" data-dropdown-css-class="select2-primary" style="width: 100%;" required>
|
|
<?php
|
|
$List = new Listdata();
|
|
$List->set_list("data_server",$SqlDataWH);
|
|
foreach ($List->get_list() as $key => $value): ?>
|
|
<option value="<?php echo $value['id']; ?>"><?php echo $value['nama_server']; ?></option>
|
|
<?php endforeach ?>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Status Pelanggan</label>
|
|
<select id="sp" class="form-control" name="sp">
|
|
<option value="">All</option>
|
|
<option value="aktif">Aktif</option>
|
|
<option value="tidak aktif" >Tidak Aktif</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Status Koneksi</label>
|
|
<select id="sk" class="form-control" name="sk">
|
|
<option value="">All</option>
|
|
<option value="On">Connected</option>
|
|
<option value="Off" >Disconnected</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Topologi ODP / ODC</label>
|
|
<select class="form-control select2bs4" name="mt">
|
|
<option value="">All</option>
|
|
<?php
|
|
$List = new Listdata();
|
|
$List->set_list("master_topologi", $SqlDataWHId);
|
|
foreach ($List->get_list() as $key => $value): ?>
|
|
<option value="<?php echo $value['id']; ?>" ><?php echo $value['nama']; ?></option>
|
|
<?php endforeach ?>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-4 unofficial-section">
|
|
<div class="form-group">
|
|
<label>Isi Pesan Siaran</label>
|
|
<textarea class="form-control" rows="11" name="pesan"></textarea>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4 unofficial-section">
|
|
<center>
|
|
<label>Foto</label>
|
|
<div class="uploadImage" data-id="siaran<?php echo $SvId; ?>">
|
|
<span>Click to upload image</span>
|
|
<img src="#" alt="Image preview">
|
|
<div class="progressContainer">
|
|
<div class="progressBar"></div>
|
|
</div>
|
|
</div>
|
|
</center>
|
|
</div>
|
|
|
|
<div class="col-md-3 official-section">
|
|
<div class="card-body">
|
|
<div class="form-group">
|
|
<label for="template">Pilih Template</label>
|
|
<select class="form-control" name="template" id="template">
|
|
<?php foreach ($templates as $tpl): ?>
|
|
<option
|
|
value="<?= htmlspecialchars($tpl['name']) ?>"
|
|
data-template='<?= json_encode($tpl, JSON_HEX_APOS | JSON_HEX_QUOT) ?>' <?= (htmlspecialchars($tpl['name']) == $pesan['nama_template']) ? 'selected' : '' ?>>
|
|
<?= htmlspecialchars($tpl['name']) ?>
|
|
</option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
<input type="hidden" name="pesan_official" id="pesan_official">
|
|
<!-- Form dinamis -->
|
|
<div id="paramForm" style="margin-top:20px;"></div>
|
|
|
|
</div>
|
|
</div>
|
|
<div class="col-md-5 official-section">
|
|
<div class="card-body" style="display:flex;justify-content:center;align-items:center;">
|
|
<!-- Preview gaya WhatsApp -->
|
|
<div id="waPreview" style="margin-top:20px;max-width:400px;font-family:sans-serif;">
|
|
<div style="background:#075E54;color:white;padding:10px;border-radius:8px 8px 0 0;">
|
|
WhatsApp Preview
|
|
</div>
|
|
<div style="border:1px solid #ccc;border-top:0;padding-top:10px;padding-left:10px;padding-right:10px;border-radius:0 0 8px 8px;background:#ECE5DD; padding-bottom: 20px;">
|
|
<div style="background:white;padding:8px;border-radius:8px;display:flex;flex-direction:column;gap:0;max-width:90%;margin-bottom:-6px;">
|
|
<div id="waHeader"></div>
|
|
<div id="waMessage"></div>
|
|
<div id="waFooter"></div>
|
|
</div>
|
|
<div id="waButtons" style="max-width:90%;"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="card-footer">
|
|
<button type="submit" class="btn btn-primary" name="kirim">Kirim Pesan</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<?php
|
|
if (isset($_POST['kirim'])) {
|
|
$type = $_POST['gateway_type'] ?? null;
|
|
$ids = $_POST['ids'] ?? [];
|
|
|
|
// Cegah implode null
|
|
if (empty($ids)) {
|
|
sweetAlert("Tidak ada server yang dipilih!", "warning");
|
|
exit;
|
|
}
|
|
|
|
$idsv = implode(", ", array_map('intval', $ids)); // sanitasi ID
|
|
$sp = $_POST['sp'] ?? null;
|
|
$sk = $_POST['sk'] ?? null;
|
|
$mt = $_POST['mt'] ?? null;
|
|
|
|
$sp1 = !empty($sp) ? " AND status = :sp" : "";
|
|
$sk1 = !empty($sk) ? " AND status_koneksi = :sk" : "";
|
|
$mt1 = !empty($mt) ? " AND id_master_topologi = :mt" : "";
|
|
|
|
$target_dir = "https://storage.manjapro.net/files/user/";
|
|
$SQL = "WHERE id_data_server IN ($idsv)" . $sp1 . $sk1 . $mt1;
|
|
|
|
try {
|
|
$stmt = $pdo->prepare("SELECT nomor_whatsapp, id_data_server FROM pelanggan $SQL");
|
|
|
|
if (!empty($sp)) $stmt->bindParam(':sp', $sp);
|
|
if (!empty($sk)) $stmt->bindParam(':sk', $sk);
|
|
if (!empty($mt)) $stmt->bindParam(':mt', $mt);
|
|
|
|
$stmt->execute();
|
|
|
|
$countInserted = 0;
|
|
while ($pecah = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
|
|
|
// ====== GATEWAY OFFICIAL ======
|
|
if (!empty($type) && $type == "official") {
|
|
$id = $pecah['id_data_server'];
|
|
$jenis = "sendMessage";
|
|
$nomor = $pecah['nomor_whatsapp'];
|
|
|
|
// Replace placeholder #no_whatsapp dengan angka murni dari nomor
|
|
$cleanNumber = preg_replace('/\D/', '', $nomor);
|
|
$message = str_replace('#no_whatsapp', $cleanNumber, $_POST['pesan_official']);
|
|
|
|
$file_url = NULL;
|
|
$apiurl = 0;
|
|
$apikey = 0;
|
|
|
|
$sqlIn = "INSERT INTO master_pesan
|
|
(id_data_server, jenis_pesan, api_url, api_key, nomor, pesan, url_file, status, gateway_type)
|
|
VALUES
|
|
(:id, :jenis, :apiurl, :apikey, :nomor, :pesan, :url_file, 'PENDING', 'official')";
|
|
}
|
|
// ====== GATEWAY UNOFFICIAL ======
|
|
else {
|
|
$stmt2 = $pdo->prepare("SELECT url_whatsapp_gateway, apiKey_whatsapp FROM data_server WHERE id = :id_data_server");
|
|
$stmt2->bindParam(':id_data_server', $pecah['id_data_server']);
|
|
$stmt2->execute();
|
|
$pecah2 = $stmt2->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if (!$pecah2) {
|
|
continue; // skip kalau data_server tidak ditemukan
|
|
}
|
|
|
|
// Cek apakah ada file yang diupload di sesi
|
|
$sessionKey = 'siaran' . $SvId;
|
|
if (isset($_SESSION['uploaded_files'][$sessionKey])) {
|
|
$id = $pecah['id_data_server'];
|
|
$jenis = "sendMediaFromUrl";
|
|
$nomor = $pecah['nomor_whatsapp'];
|
|
$message = $_POST['pesan'];
|
|
$file_url = $target_dir . $_SESSION['uploaded_files'][$sessionKey];
|
|
$apiurl = $pecah2['url_whatsapp_gateway'];
|
|
$apikey = $pecah2['apiKey_whatsapp'];
|
|
|
|
$sqlIn = "INSERT INTO master_pesan
|
|
(id_data_server, jenis_pesan, api_url, api_key, nomor, pesan, url_file, status, gateway_type)
|
|
VALUES
|
|
(:id, :jenis, :apiurl, :apikey, :nomor, :pesan, :url_file, 'PENDING', 'unofficial')";
|
|
} else {
|
|
$id = $pecah['id_data_server'];
|
|
$jenis = "sendMessage";
|
|
$nomor = $pecah['nomor_whatsapp'];
|
|
$message = $_POST['pesan'];
|
|
$apiurl = $pecah2['url_whatsapp_gateway'];
|
|
$apikey = $pecah2['apiKey_whatsapp'];
|
|
$file_url = NULL;
|
|
|
|
$sqlIn = "INSERT INTO master_pesan
|
|
(id_data_server, jenis_pesan, api_url, api_key, nomor, pesan, status, gateway_type)
|
|
VALUES
|
|
(:id, :jenis, :apiurl, :apikey, :nomor, :pesan, 'PENDING', 'unofficial')";
|
|
}
|
|
}
|
|
|
|
// === Insert ke tabel master_pesan ===
|
|
$stmtInsert = $pdo->prepare($sqlIn);
|
|
$stmtInsert->bindParam(':id', $id);
|
|
$stmtInsert->bindParam(':jenis', $jenis);
|
|
$stmtInsert->bindParam(':apiurl', $apiurl);
|
|
$stmtInsert->bindParam(':apikey', $apikey);
|
|
$stmtInsert->bindParam(':nomor', $nomor);
|
|
$stmtInsert->bindParam(':pesan', $message);
|
|
|
|
if (strpos($sqlIn, ':url_file') !== false) {
|
|
$stmtInsert->bindParam(':url_file', $file_url);
|
|
}
|
|
|
|
$stmtInsert->execute();
|
|
$countInserted++;
|
|
}
|
|
|
|
// Bersihkan sesi upload jika ada
|
|
if (isset($_SESSION['uploaded_files']['siaran' . $SvId])) {
|
|
unset($_SESSION['uploaded_files']['siaran' . $SvId]);
|
|
}
|
|
|
|
if ($countInserted > 0) {
|
|
sweetAlert("Pesan ($countInserted) akan segera dikirim.", "success");
|
|
} else {
|
|
sweetAlert("Tidak ada data pelanggan yang cocok.", "info");
|
|
}
|
|
|
|
} catch (PDOException $e) {
|
|
sweetAlert("Error Database: " . $e->getMessage(), "error");
|
|
} catch (Exception $e) {
|
|
sweetAlert("Kesalahan Umum: " . $e->getMessage(), "error");
|
|
}
|
|
}
|
|
?>
|
|
|
|
|
|
|
|
<script>
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
const gatewaySelect = document.getElementById("gateway_type");
|
|
const unofficialSections = document.querySelectorAll(".unofficial-section");
|
|
const officialSections = document.querySelectorAll(".official-section");
|
|
|
|
const templateSelect = document.getElementById("template");
|
|
const paramForm = document.getElementById("paramForm");
|
|
const waHeader = document.getElementById("waHeader");
|
|
const waMessage = document.getElementById("waMessage");
|
|
const waFooter = document.getElementById("waFooter");
|
|
const waButtons = document.getElementById("waButtons");
|
|
const waPostmessage = document.getElementById("pesan_official");
|
|
|
|
const SvId = '<?= encrypt_url(json_encode([$SvId, "informasi"])); ?>';
|
|
let templateLoaded = false;
|
|
|
|
// ============================================================
|
|
// DEFINISI SEMUA FUNCTION UTAMA DI AWAL (biar pasti dikenal)
|
|
// ============================================================
|
|
|
|
function updatePreview() {
|
|
let preview = waMessage.getAttribute("data-original") || "";
|
|
document.querySelectorAll("#paramForm input[data-placeholder]").forEach(input => {
|
|
let ph = input.dataset.placeholder;
|
|
let val = input.value || ph;
|
|
preview = preview.replace(ph, val);
|
|
});
|
|
|
|
preview = preview
|
|
.replace(/\*(.*?)\*/g, "<b>$1</b>")
|
|
.replace(/__(.*?)__/g, "<u>$1</u>")
|
|
.replace(/_(.*?)_/g, "<i>$1</i>")
|
|
.replace(/~(.*?)~/g, "<s>$1</s>")
|
|
.replace(/\n/g, "<br>");
|
|
waMessage.innerHTML = preview;
|
|
|
|
const payload = generatePayload();
|
|
if (waPostmessage && payload) {
|
|
waPostmessage.value = JSON.stringify(payload, null, 2);
|
|
}
|
|
}
|
|
|
|
function updateHeaderImage(input) {
|
|
const img = document.getElementById("header-img-preview");
|
|
if (img) img.src = input.value || "";
|
|
updatePreview();
|
|
}
|
|
|
|
function generatePayload() {
|
|
const template = templateSelect.value;
|
|
if (!template) return null;
|
|
|
|
const data = {
|
|
messaging_product: "whatsapp",
|
|
recipient_type: "individual",
|
|
to: "#no_whatsapp",
|
|
type: "template",
|
|
template: {
|
|
name: template,
|
|
language: { code: "id" },
|
|
components: []
|
|
}
|
|
};
|
|
|
|
const headerImageInput = document.querySelector("input[name='header_image']");
|
|
if (headerImageInput?.value) {
|
|
data.template.components.push({
|
|
type: "header",
|
|
parameters: [{ type: "image", image: { link: headerImageInput.value } }]
|
|
});
|
|
}
|
|
|
|
const bodyParams = [];
|
|
document.querySelectorAll("input[name^='body_']").forEach(input => {
|
|
if (input.value.trim()) {
|
|
bodyParams.push({ type: "text", text: input.value });
|
|
}
|
|
});
|
|
if (bodyParams.length > 0) {
|
|
data.template.components.push({ type: "body", parameters: bodyParams });
|
|
}
|
|
|
|
document.querySelectorAll("input[name^='btn_']").forEach(input => {
|
|
if (input.value.trim()) {
|
|
let [_, index] = input.name.split("_");
|
|
data.template.components.push({
|
|
type: "button",
|
|
sub_type: "url",
|
|
index: parseInt(index),
|
|
parameters: [{ type: "text", text: input.value }]
|
|
});
|
|
}
|
|
});
|
|
|
|
return data;
|
|
}
|
|
|
|
function initImageUploader() {
|
|
const imgInput = document.getElementById("image_update_value");
|
|
const imgPreview = document.getElementById("header-img-preview");
|
|
const container = document.getElementById("upload_container");
|
|
if (!imgInput || !container) return;
|
|
|
|
const fileInput = document.createElement("input");
|
|
fileInput.type = "file";
|
|
fileInput.accept = "image/*";
|
|
fileInput.className = "form-control mt-2";
|
|
fileInput.addEventListener("change", async (e) => {
|
|
const file = e.target.files[0];
|
|
if (!file) return;
|
|
|
|
const reader = new FileReader();
|
|
reader.onload = ev => { if (imgPreview) imgPreview.src = ev.target.result; };
|
|
reader.readAsDataURL(file);
|
|
|
|
const formData = new FormData();
|
|
formData.append("file", file);
|
|
|
|
try {
|
|
const res = await fetch("controller/upload_image_pesan_siaran.php", {
|
|
method: "POST",
|
|
body: formData
|
|
});
|
|
const data = await res.json();
|
|
|
|
if (data.status === "success" && data.url) {
|
|
imgInput.value = data.url;
|
|
updateHeaderImage(imgInput);
|
|
} else {
|
|
alert("Upload gagal: " + (data.message || "Unknown error"));
|
|
}
|
|
} catch (err) {
|
|
alert("Upload gagal. Cek koneksi atau server upload.");
|
|
console.error(err);
|
|
}
|
|
});
|
|
|
|
container.innerHTML = "";
|
|
container.appendChild(fileInput);
|
|
}
|
|
|
|
// ============================================================
|
|
// RENDER PARAMETER DINAMIS (dengan binding event via JS)
|
|
// ============================================================
|
|
function renderParamForm(tpl) {
|
|
paramForm.innerHTML = "";
|
|
waHeader.innerHTML = "";
|
|
waMessage.innerHTML = "";
|
|
waFooter.innerHTML = "";
|
|
waButtons.innerHTML = "";
|
|
|
|
if (!tpl?.components) return;
|
|
|
|
let formHtml = "<h5 class='text-center'><b>Parameter Wajib</b></h5><hr>";
|
|
let previewBody = "";
|
|
|
|
tpl.components.forEach((comp) => {
|
|
// HEADER IMAGE
|
|
if (comp.type === "HEADER" && comp.format === "IMAGE") {
|
|
let defaultImg = comp.example?.header_handle?.[0] || "";
|
|
formHtml += `
|
|
<div class="form-group">
|
|
<label>Gambar</label>
|
|
<input class="form-control" type="hidden" id="image_update_value"
|
|
name="header_image" value="${defaultImg}" required>
|
|
<div id="upload_container"></div>
|
|
</div>`;
|
|
waHeader.innerHTML = `<img id="header-img-preview" src="${defaultImg}" style="max-width:100%;border-radius:6px;"><br>`;
|
|
}
|
|
|
|
// BODY PARAMS
|
|
if (comp.type === "BODY" && comp.text) {
|
|
waMessage.setAttribute("data-original", comp.text);
|
|
let regex = /\{\{(\d+)\}\}/g, match, idx = 0;
|
|
while ((match = regex.exec(comp.text)) !== null) {
|
|
let paramNum = match[1];
|
|
formHtml += `
|
|
<div class="form-group">
|
|
<label>Parameter : {{${paramNum}}}</label>
|
|
<input class="form-control body-param" type="text"
|
|
name="body_${paramNum}" data-placeholder="{{${paramNum}}}" required>
|
|
</div>`;
|
|
idx++;
|
|
}
|
|
previewBody += comp.text.replace(/\n/g, "<br>");
|
|
}
|
|
if (comp.type === "FOOTER" && comp.text) {
|
|
waFooter.innerHTML = `<small class="text-secondary">${comp.text}</small><br>`;
|
|
}
|
|
|
|
if (comp.type === "BUTTONS" && comp.buttons) {
|
|
comp.buttons.forEach((btn, bi) => {
|
|
if (btn.type === "URL") {
|
|
let btnText = btn.text;
|
|
let url = btn.url;
|
|
let regex = /\{\{(\d+)\}\}/g;
|
|
let match, idx = 0;
|
|
while ((match = regex.exec(url)) !== null) {
|
|
let paramNum = match[1];
|
|
let dbVal = btn.dbParams ? (btn.dbParams[idx] || "") : "";
|
|
formHtml += `<div class="form-group">
|
|
<label>Button ${bi+1} Param ${paramNum}:</label><br>
|
|
<input class="form-control" type="text" name="btn_${bi}_${paramNum}"
|
|
value="${dbVal}"
|
|
oninput="updatePreview()" data-placeholder="{{${paramNum}}}" required>
|
|
</div>`;
|
|
idx++;
|
|
}
|
|
|
|
waButtons.innerHTML += `<a href="#"
|
|
style="display:flex;align-items:center;justify-content:center;
|
|
background:#fff;color:green;padding:8px 12px;
|
|
border-radius:6px;border-top:1px solid #c0c0c0;
|
|
text-decoration:none;position:relative;z-index:10;">
|
|
<i class="fa fa-share-square" style="margin-right:8px; font-size:16px;"></i>
|
|
<span>${btnText}</span>
|
|
</a>`;
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
paramForm.innerHTML = formHtml;
|
|
waMessage.innerHTML = previewBody;
|
|
|
|
// Tambahkan listener dinamis untuk semua input yang baru dibuat
|
|
paramForm.querySelectorAll("input[data-placeholder]").forEach(input => {
|
|
input.addEventListener("input", updatePreview);
|
|
});
|
|
const imgInput = document.getElementById("image_update_value");
|
|
if (imgInput) imgInput.addEventListener("input", e => updateHeaderImage(e.target));
|
|
|
|
updatePreview();
|
|
initImageUploader();
|
|
}
|
|
|
|
// ============================================================
|
|
// FETCH TEMPLATE OFFICIAL
|
|
// ============================================================
|
|
function loadOfficialTemplates() {
|
|
fetch(`controller/get_template_official.php?id=${SvId}`)
|
|
.then(res => res.json())
|
|
.then(data => {
|
|
if (data.error) {
|
|
templateSelect.innerHTML = `<option disabled selected>${data.error}</option>`;
|
|
return;
|
|
}
|
|
|
|
const templates = Array.isArray(data.templates) ? data.templates : [];
|
|
const filtered = templates.filter(t => t.name?.startsWith("informasi_"));
|
|
|
|
if (filtered.length === 0) {
|
|
templateSelect.innerHTML = `<option disabled selected>Tidak ada template informasi_</option>`;
|
|
return;
|
|
}
|
|
|
|
templateSelect.innerHTML = "";
|
|
filtered.forEach(tpl => {
|
|
const opt = document.createElement("option");
|
|
opt.value = tpl.name;
|
|
opt.textContent = tpl.name;
|
|
opt.dataset.template = JSON.stringify(tpl);
|
|
templateSelect.appendChild(opt);
|
|
});
|
|
|
|
if (templateSelect.options.length > 0) {
|
|
templateSelect.selectedIndex = 0;
|
|
const firstTpl = JSON.parse(templateSelect.options[0].dataset.template);
|
|
renderParamForm(firstTpl);
|
|
}
|
|
})
|
|
.catch(err => {
|
|
console.error("Gagal load template:", err);
|
|
templateSelect.innerHTML = `<option disabled selected>Gagal load template</option>`;
|
|
});
|
|
}
|
|
|
|
// ============================================================
|
|
// TOGGLE GATEWAY VIEW
|
|
// ============================================================
|
|
function toggleGatewayView() {
|
|
const val = gatewaySelect.value;
|
|
|
|
if (val === "unofficial") {
|
|
unofficialSections.forEach(el => el.style.display = "block");
|
|
officialSections.forEach(el => el.style.display = "none");
|
|
} else if (val === "official") {
|
|
unofficialSections.forEach(el => el.style.display = "none");
|
|
officialSections.forEach(el => el.style.display = "block");
|
|
|
|
if (!templateLoaded) {
|
|
loadOfficialTemplates();
|
|
templateLoaded = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ============================================================
|
|
// EVENT LISTENERS
|
|
// ============================================================
|
|
templateSelect.addEventListener("change", function () {
|
|
const opt = this.options[this.selectedIndex];
|
|
if (!opt?.dataset.template) return;
|
|
const tpl = JSON.parse(opt.dataset.template);
|
|
renderParamForm(tpl);
|
|
});
|
|
|
|
gatewaySelect.addEventListener("change", toggleGatewayView);
|
|
toggleGatewayView();
|
|
});
|
|
</script>
|
|
|
|
|