commit 04/02/2026
This commit is contained in:
1698
html/semiauto/assets/css/datatables.css
Normal file
1698
html/semiauto/assets/css/datatables.css
Normal file
File diff suppressed because it is too large
Load Diff
42
html/semiauto/assets/js/common.js
Normal file
42
html/semiauto/assets/js/common.js
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Fetch API helper function
|
||||
* @param {string} endpoint Endpoint URL
|
||||
* @param {string} method Method (GET, POST, etc.)
|
||||
* @param {Object} headers Headers to include in the request
|
||||
* @param {Object} body Body of the request
|
||||
* @param {Function} cbOK Callback function for successful response
|
||||
* @param {Function} cbError Callback function for error response
|
||||
*/
|
||||
function fetchAPI(endpoint, method, headers = {}, body = null, cbOK, cbError) {
|
||||
let url = window.location.origin + "/api/" + endpoint;
|
||||
let options = {
|
||||
method: method,
|
||||
headers: headers
|
||||
}
|
||||
if (body !== null) {
|
||||
options.body = JSON.stringify(body);
|
||||
if (!options.headers['Content-Type']) {
|
||||
options.headers['Content-Type'] = 'application/json';
|
||||
}
|
||||
}
|
||||
fetch(url, options)
|
||||
.then(async (response) => {
|
||||
if (!response.ok) {
|
||||
let msg;
|
||||
try {
|
||||
let _xxx = await response.json();
|
||||
msg = _xxx.message || response.statusText;
|
||||
} catch {
|
||||
msg = await response.statusText;
|
||||
}
|
||||
throw new Error(msg);
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
cbOK(data);
|
||||
})
|
||||
.catch(error => {
|
||||
cbError(error);
|
||||
});
|
||||
}
|
||||
@@ -12,15 +12,14 @@ let $enable_japanese = null;
|
||||
let $enable_arabic = null;
|
||||
let $enable_local = null;
|
||||
|
||||
let $tbody_message = null;
|
||||
let $tbody_broadcastzones = null;
|
||||
message_table = null;
|
||||
$select_broadcastzones = null;
|
||||
|
||||
let $select_airline = null;
|
||||
let $select_city = null;
|
||||
let $select_places = null;
|
||||
let $select_shalat = null;
|
||||
let $select_reason = null;
|
||||
let $select_conveyorbelt = null;
|
||||
let $select_procedure = null;
|
||||
let $select_compensation = null;
|
||||
|
||||
@@ -60,48 +59,7 @@ let selected_messages = [];
|
||||
* @property {string} value - The value of the variable
|
||||
*/
|
||||
|
||||
/**
|
||||
* Fetch API helper function
|
||||
* @param {string} endpoint Endpoint URL
|
||||
* @param {string} method Method (GET, POST, etc.)
|
||||
* @param {Object} headers Headers to include in the request
|
||||
* @param {Object} body Body of the request
|
||||
* @param {Function} cbOK Callback function for successful response
|
||||
* @param {Function} cbError Callback function for error response
|
||||
*/
|
||||
function fetchAPI(endpoint, method, headers = {}, body = null, cbOK, cbError) {
|
||||
let url = window.location.origin + "/api/" + endpoint;
|
||||
let options = {
|
||||
method: method,
|
||||
headers: headers
|
||||
}
|
||||
if (body !== null) {
|
||||
options.body = JSON.stringify(body);
|
||||
if (!options.headers['Content-Type']) {
|
||||
options.headers['Content-Type'] = 'application/json';
|
||||
}
|
||||
}
|
||||
fetch(url, options)
|
||||
.then(async (response) => {
|
||||
if (!response.ok) {
|
||||
let msg;
|
||||
try {
|
||||
let _xxx = await response.json();
|
||||
msg = _xxx.message || response.statusText;
|
||||
} catch {
|
||||
msg = await response.statusText;
|
||||
}
|
||||
throw new Error(msg);
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
cbOK(data);
|
||||
})
|
||||
.catch(error => {
|
||||
cbError(error);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
window.semiautodata = {
|
||||
/** @type {message[]} */
|
||||
@@ -146,20 +104,20 @@ window.semiautodata = {
|
||||
|
||||
Add_Message: (str) => {
|
||||
if (str == null || typeof str !== 'string' || str.trim().length === 0) {
|
||||
console.warn("Add_Message: input must be a non-empty string");
|
||||
//console.warn("Add_Message: input must be a non-empty string");
|
||||
return false;
|
||||
}
|
||||
|
||||
const parts = str.split(';');
|
||||
if (!Array.isArray(parts) || parts.length !== 4) {
|
||||
console.warn("Add_Message: input must contain exactly 4 semicolon-separated parts");
|
||||
//console.warn("Add_Message: input must contain exactly 4 semicolon-separated parts");
|
||||
return false;
|
||||
}
|
||||
|
||||
const [idPart, description, language, message_details] = parts.map(p => p.trim());
|
||||
const id = Number(idPart);
|
||||
if (!Number.isInteger(id)) {
|
||||
console.warn("Add_Message: first part must be an integer id");
|
||||
//console.warn("Add_Message: first part must be an integer id");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -171,7 +129,7 @@ window.semiautodata = {
|
||||
});
|
||||
|
||||
if (duplicate) {
|
||||
console.warn(`Add_Message: message with id ${id} and language "${language}" already exists`);
|
||||
//console.warn(`Add_Message: message with id ${id} and language "${language}" already exists`);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -186,22 +144,22 @@ window.semiautodata = {
|
||||
|
||||
Add_Airline: (str) => {
|
||||
if (str == null || typeof str !== 'string' || str.trim().length === 0) {
|
||||
console.warn("Add_Airline: input must be a non-empty string");
|
||||
//console.warn("Add_Airline: input must be a non-empty string");
|
||||
return false;
|
||||
}
|
||||
const parts = str.split(';').map(p => p.trim());
|
||||
if (!Array.isArray(parts) || parts.length !== 2) {
|
||||
console.warn("Add_Airline: input must contain exactly 2 semicolon-separated parts");
|
||||
//console.warn("Add_Airline: input must contain exactly 2 semicolon-separated parts");
|
||||
return false;
|
||||
}
|
||||
const [tag, value] = parts;
|
||||
if (!tag || !value) {
|
||||
console.warn("Add_Airline: both tag and value must be non-empty");
|
||||
//console.warn("Add_Airline: both tag and value must be non-empty");
|
||||
return false;
|
||||
}
|
||||
const duplicate = window.semiautodata.airlines.some(a => (a && (a.tag || "").trim() === tag && (a.value || "").trim() === value));
|
||||
if (duplicate) {
|
||||
console.warn(`Add_Airline: airline "${tag}" with value "${value}" already exists`);
|
||||
//console.warn(`Add_Airline: airline "${tag}" with value "${value}" already exists`);
|
||||
return false;
|
||||
}
|
||||
window.semiautodata.airlines.push({ tag, value });
|
||||
@@ -210,22 +168,22 @@ window.semiautodata = {
|
||||
|
||||
Add_City: (str) => {
|
||||
if (str == null || typeof str !== 'string' || str.trim().length === 0) {
|
||||
console.warn("Add_City: input must be a non-empty string");
|
||||
//console.warn("Add_City: input must be a non-empty string");
|
||||
return false;
|
||||
}
|
||||
const parts = str.split(';').map(p => p.trim());
|
||||
if (!Array.isArray(parts) || parts.length !== 2) {
|
||||
console.warn("Add_City: input must contain exactly 2 semicolon-separated parts");
|
||||
//console.warn("Add_City: input must contain exactly 2 semicolon-separated parts");
|
||||
return false;
|
||||
}
|
||||
const [tag, value] = parts;
|
||||
if (!tag || !value) {
|
||||
console.warn("Add_City: both tag and value must be non-empty");
|
||||
//console.warn("Add_City: both tag and value must be non-empty");
|
||||
return false;
|
||||
}
|
||||
const duplicate = window.semiautodata.cities.some(c => (c && (c.tag || "").trim() === tag && (c.value || "").trim() === value));
|
||||
if (duplicate) {
|
||||
console.warn(`Add_City: city "${tag}" with value "${value}" already exists`);
|
||||
//console.warn(`Add_City: city "${tag}" with value "${value}" already exists`);
|
||||
return false;
|
||||
}
|
||||
window.semiautodata.cities.push({ tag, value });
|
||||
@@ -234,22 +192,22 @@ window.semiautodata = {
|
||||
|
||||
Add_Place: (str) => {
|
||||
if (str == null || typeof str !== 'string' || str.trim().length === 0) {
|
||||
console.warn("Add_Place: input must be a non-empty string");
|
||||
//console.warn("Add_Place: input must be a non-empty string");
|
||||
return false;
|
||||
}
|
||||
const parts = str.split(';').map(p => p.trim());
|
||||
if (!Array.isArray(parts) || parts.length !== 2) {
|
||||
console.warn("Add_Place: input must contain exactly 2 semicolon-separated parts");
|
||||
//console.warn("Add_Place: input must contain exactly 2 semicolon-separated parts");
|
||||
return false;
|
||||
}
|
||||
const [tag, value] = parts;
|
||||
if (!tag || !value) {
|
||||
console.warn("Add_Place: both tag and value must be non-empty");
|
||||
//console.warn("Add_Place: both tag and value must be non-empty");
|
||||
return false;
|
||||
}
|
||||
const duplicate = window.semiautodata.places.some(p => (p && (p.tag || "").trim() === tag && (p.value || "").trim() === value));
|
||||
if (duplicate) {
|
||||
console.warn(`Add_Place: place "${tag}" with value "${value}" already exists`);
|
||||
//console.warn(`Add_Place: place "${tag}" with value "${value}" already exists`);
|
||||
return false;
|
||||
}
|
||||
window.semiautodata.places.push({ tag, value });
|
||||
@@ -258,22 +216,22 @@ window.semiautodata = {
|
||||
|
||||
Add_Shalat: (str) => {
|
||||
if (str == null || typeof str !== 'string' || str.trim().length === 0) {
|
||||
console.warn("Add_Shalat: input must be a non-empty string");
|
||||
//console.warn("Add_Shalat: input must be a non-empty string");
|
||||
return false;
|
||||
}
|
||||
const parts = str.split(';').map(p => p.trim());
|
||||
if (!Array.isArray(parts) || parts.length !== 2) {
|
||||
console.warn("Add_Shalat: input must contain exactly 2 semicolon-separated parts");
|
||||
//console.warn("Add_Shalat: input must contain exactly 2 semicolon-separated parts");
|
||||
return false;
|
||||
}
|
||||
const [tag, value] = parts;
|
||||
if (!tag || !value) {
|
||||
console.warn("Add_Shalat: both tag and value must be non-empty");
|
||||
//console.warn("Add_Shalat: both tag and value must be non-empty");
|
||||
return false;
|
||||
}
|
||||
const duplicate = window.semiautodata.shalat.some(s => (s && (s.tag || "").trim() === tag && (s.value || "").trim() === value));
|
||||
if (duplicate) {
|
||||
console.warn(`Add_Shalat: shalat "${tag}" with value "${value}" already exists`);
|
||||
//console.warn(`Add_Shalat: shalat "${tag}" with value "${value}" already exists`);
|
||||
return false;
|
||||
}
|
||||
window.semiautodata.shalat.push({ tag, value });
|
||||
@@ -282,22 +240,22 @@ window.semiautodata = {
|
||||
|
||||
Add_Reason: (str) => {
|
||||
if (str == null || typeof str !== 'string' || str.trim().length === 0) {
|
||||
console.warn("Add_Reason: input must be a non-empty string");
|
||||
//console.warn("Add_Reason: input must be a non-empty string");
|
||||
return false;
|
||||
}
|
||||
const parts = str.split(';').map(p => p.trim());
|
||||
if (!Array.isArray(parts) || parts.length !== 2) {
|
||||
console.warn("Add_Reason: input must contain exactly 2 semicolon-separated parts");
|
||||
//console.warn("Add_Reason: input must contain exactly 2 semicolon-separated parts");
|
||||
return false;
|
||||
}
|
||||
const [tag, value] = parts;
|
||||
if (!tag || !value) {
|
||||
console.warn("Add_Reason: both tag and value must be non-empty");
|
||||
//console.warn("Add_Reason: both tag and value must be non-empty");
|
||||
return false;
|
||||
}
|
||||
const duplicate = window.semiautodata.reasons.some(r => (r && (r.tag || "").trim() === tag && (r.value || "").trim() === value));
|
||||
if (duplicate) {
|
||||
console.warn(`Add_Reason: reason "${tag}" with value "${value}" already exists`);
|
||||
//console.warn(`Add_Reason: reason "${tag}" with value "${value}" already exists`);
|
||||
return false;
|
||||
}
|
||||
window.semiautodata.reasons.push({ tag, value });
|
||||
@@ -306,22 +264,22 @@ window.semiautodata = {
|
||||
|
||||
Add_Procedure: (str) => {
|
||||
if (str == null || typeof str !== 'string' || str.trim().length === 0) {
|
||||
console.warn("Add_Procedure: input must be a non-empty string");
|
||||
//console.warn("Add_Procedure: input must be a non-empty string");
|
||||
return false;
|
||||
}
|
||||
const parts = str.split(';').map(p => p.trim());
|
||||
if (!Array.isArray(parts) || parts.length !== 2) {
|
||||
console.warn("Add_Procedure: input must contain exactly 2 semicolon-separated parts");
|
||||
//console.warn("Add_Procedure: input must contain exactly 2 semicolon-separated parts");
|
||||
return false;
|
||||
}
|
||||
const [tag, value] = parts;
|
||||
if (!tag || !value) {
|
||||
console.warn("Add_Procedure: both tag and value must be non-empty");
|
||||
//console.warn("Add_Procedure: both tag and value must be non-empty");
|
||||
return false;
|
||||
}
|
||||
const duplicate = window.semiautodata.procedures.some(p => (p && (p.tag || "").trim() === tag && (p.value || "").trim() === value));
|
||||
if (duplicate) {
|
||||
console.warn(`Add_Procedure: procedure "${tag}" with value "${value}" already exists`);
|
||||
//console.warn(`Add_Procedure: procedure "${tag}" with value "${value}" already exists`);
|
||||
return false;
|
||||
}
|
||||
window.semiautodata.procedures.push({ tag, value });
|
||||
@@ -330,22 +288,22 @@ window.semiautodata = {
|
||||
|
||||
Add_Compensation: (str) => {
|
||||
if (str == null || typeof str !== 'string' || str.trim().length === 0) {
|
||||
console.warn("Add_Compensation: input must be a non-empty string");
|
||||
//console.warn("Add_Compensation: input must be a non-empty string");
|
||||
return false;
|
||||
}
|
||||
const parts = str.split(';').map(p => p.trim());
|
||||
if (!Array.isArray(parts) || parts.length !== 2) {
|
||||
console.warn("Add_Compensation: input must contain exactly 2 semicolon-separated parts");
|
||||
//console.warn("Add_Compensation: input must contain exactly 2 semicolon-separated parts");
|
||||
return false;
|
||||
}
|
||||
const [tag, value] = parts;
|
||||
if (!tag || !value) {
|
||||
console.warn("Add_Compensation: both tag and value must be non-empty");
|
||||
//console.warn("Add_Compensation: both tag and value must be non-empty");
|
||||
return false;
|
||||
}
|
||||
const duplicate = window.semiautodata.compensation.some(c => (c && (c.tag || "").trim() === tag && (c.value || "").trim() === value));
|
||||
if (duplicate) {
|
||||
console.warn(`Add_Compensation: compensation "${tag}" with value "${value}" already exists`);
|
||||
//console.warn(`Add_Compensation: compensation "${tag}" with value "${value}" already exists`);
|
||||
return false;
|
||||
}
|
||||
window.semiautodata.compensation.push({ tag, value });
|
||||
@@ -354,22 +312,22 @@ window.semiautodata = {
|
||||
|
||||
Add_Greeting: (str) => {
|
||||
if (str == null || typeof str !== 'string' || str.trim().length === 0) {
|
||||
console.warn("Add_Greeting: input must be a non-empty string");
|
||||
//console.warn("Add_Greeting: input must be a non-empty string");
|
||||
return false;
|
||||
}
|
||||
const parts = str.split(';').map(p => p.trim());
|
||||
if (!Array.isArray(parts) || parts.length !== 2) {
|
||||
console.warn("Add_Greeting: input must contain exactly 2 semicolon-separated parts");
|
||||
//console.warn("Add_Greeting: input must contain exactly 2 semicolon-separated parts");
|
||||
return false;
|
||||
}
|
||||
const [tag, value] = parts;
|
||||
if (!tag || !value) {
|
||||
console.warn("Add_Greeting: both tag and value must be non-empty");
|
||||
//console.warn("Add_Greeting: both tag and value must be non-empty");
|
||||
return false;
|
||||
}
|
||||
const duplicate = window.semiautodata.greetings.some(g => (g && (g.tag || "").trim() === tag && (g.value || "").trim() === value));
|
||||
if (duplicate) {
|
||||
console.warn(`Add_Greeting: greeting "${tag}" with value "${value}" already exists`);
|
||||
//console.warn(`Add_Greeting: greeting "${tag}" with value "${value}" already exists`);
|
||||
return false;
|
||||
}
|
||||
window.semiautodata.greetings.push({ tag, value });
|
||||
@@ -378,18 +336,18 @@ window.semiautodata = {
|
||||
|
||||
Add_BroadcastZone: (str) => {
|
||||
if (str == null || typeof str !== 'string' || str.trim().length === 0) {
|
||||
console.warn("Add_BroadcastZone: input must be a non-empty string");
|
||||
//console.warn("Add_BroadcastZone: input must be a non-empty string");
|
||||
return false;
|
||||
}
|
||||
const value = str.trim();
|
||||
if (value.length === 0) {
|
||||
console.warn("Add_BroadcastZone: value must be non-empty");
|
||||
//console.warn("Add_BroadcastZone: value must be non-empty");
|
||||
return false;
|
||||
}
|
||||
|
||||
const duplicate = window.semiautodata.broadcastzones.some(b => (b || "").trim() === value);
|
||||
if (duplicate) {
|
||||
console.warn(`Add_BroadcastZone: broadcast zone "${value}" already exists`);
|
||||
//console.warn(`Add_BroadcastZone: broadcast zone "${value}" already exists`);
|
||||
return false;
|
||||
}
|
||||
window.semiautodata.broadcastzones.push(value);
|
||||
@@ -406,34 +364,34 @@ function reload_database() {
|
||||
fetchAPI("Initialize", "GET", {}, null, (data) => {
|
||||
//TODO data masih dalam bentuk array of string, mesti diubah ke array of object
|
||||
window.semiautodata.Clear();
|
||||
if (data.messages && Array.isArray(data.messages)) {
|
||||
if (data.messages && Array.isArray(data.messages) && data.messages.length > 0) {
|
||||
for (let msg of data.messages) window.semiautodata.Add_Message(msg);
|
||||
}
|
||||
if (data.airlines && Array.isArray(data.airlines)) {
|
||||
if (data.airlines && Array.isArray(data.airlines) && data.airlines.length > 0) {
|
||||
for (let airline of data.airlines) window.semiautodata.Add_Airline(airline);
|
||||
}
|
||||
if (data.cities && Array.isArray(data.cities)) {
|
||||
if (data.cities && Array.isArray(data.cities) && data.cities.length > 0) {
|
||||
for (let city of data.cities) window.semiautodata.Add_City(city);
|
||||
}
|
||||
if (data.places && Array.isArray(data.places)) {
|
||||
if (data.places && Array.isArray(data.places) && data.places.length > 0) {
|
||||
for (let place of data.places) window.semiautodata.Add_Place(place);
|
||||
}
|
||||
if (data.shalat && Array.isArray(data.shalat)) {
|
||||
if (data.shalat && Array.isArray(data.shalat) && data.shalat.length > 0) {
|
||||
for (let shalat of data.shalat) window.semiautodata.Add_Shalat(shalat);
|
||||
}
|
||||
if (data.reasons && Array.isArray(data.reasons)) {
|
||||
if (data.reasons && Array.isArray(data.reasons) && data.reasons.length > 0) {
|
||||
for (let reason of data.reasons) window.semiautodata.Add_Reason(reason);
|
||||
}
|
||||
if (data.procedures && Array.isArray(data.procedures)) {
|
||||
if (data.procedures && Array.isArray(data.procedures) && data.procedures.length > 0) {
|
||||
for (let procedure of data.procedures) window.semiautodata.Add_Procedure(procedure);
|
||||
}
|
||||
if (data.compensation && Array.isArray(data.compensation)) {
|
||||
if (data.compensation && Array.isArray(data.compensation) && data.compensation.length > 0) {
|
||||
for (let compensation of data.compensation) window.semiautodata.Add_Compensation(compensation);
|
||||
}
|
||||
if (data.greetings && Array.isArray(data.greetings)) {
|
||||
if (data.greetings && Array.isArray(data.greetings) && data.greetings.length > 0) {
|
||||
for (let greeting of data.greetings) window.semiautodata.Add_Greeting(greeting);
|
||||
}
|
||||
if (data.broadcastzones && Array.isArray(data.broadcastzones)) {
|
||||
if (data.broadcastzones && Array.isArray(data.broadcastzones) && data.broadcastzones.length > 0) {
|
||||
for (let broadcastzone of data.broadcastzones) window.semiautodata.Add_BroadcastZone(broadcastzone);
|
||||
}
|
||||
fill_items();
|
||||
@@ -590,7 +548,7 @@ function update_preview(language) {
|
||||
}
|
||||
}
|
||||
if (text.indexOf('[BCB]') !== -1) {
|
||||
let bcbTag = $select_bcb.val();
|
||||
let bcbTag = $input_conveyorbelt.val();
|
||||
if (ValidString(bcbTag)) {
|
||||
text = text.replace(/\[BCB\]/g, bcbTag);
|
||||
}
|
||||
@@ -668,9 +626,55 @@ function update_all_previews() {
|
||||
check_complete_message();
|
||||
}
|
||||
|
||||
// helper to map language string to preview & checkbox
|
||||
function applyLang(lang, value, checked) {
|
||||
const l = (lang || "").toString().trim().toLowerCase();
|
||||
if (l.startsWith("indonesia")) {
|
||||
if (checked) $preview_indonesia.text(value); else $preview_indonesia.empty();
|
||||
$enable_indonesia.prop("checked", !!checked);
|
||||
return true;
|
||||
}
|
||||
if (l.startsWith("english")) {
|
||||
if (checked) $preview_english.text(value); else $preview_english.empty();
|
||||
$enable_english.prop("checked", !!checked);
|
||||
return true;
|
||||
}
|
||||
if (l.startsWith("chinese")) {
|
||||
if (checked) $preview_chinese.text(value); else $preview_chinese.empty();
|
||||
$enable_chinese.prop("checked", !!checked);
|
||||
return true;
|
||||
}
|
||||
if (l.startsWith("japanese")) {
|
||||
if (checked) $preview_japanese.text(value); else $preview_japanese.empty();
|
||||
$enable_japanese.prop("checked", !!checked);
|
||||
return true;
|
||||
}
|
||||
if (l.startsWith("arabic")) {
|
||||
if (checked) $preview_arabic.text(value); else $preview_arabic.empty();
|
||||
$enable_arabic.prop("checked", !!checked);
|
||||
return true;
|
||||
}
|
||||
if (l.startsWith("local")) {
|
||||
if (checked) $preview_local.text(value); else $preview_local.empty();
|
||||
$enable_local.prop("checked", !!checked);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// helper to clear previews for a given group id
|
||||
function clearGroupPreviews(gid) {
|
||||
if (!window.semiautodata || !Array.isArray(window.semiautodata.messages)) return;
|
||||
const sameMsgs = window.semiautodata.messages.filter(m => Number(m.id) === Number(gid));
|
||||
for (let m of sameMsgs) {
|
||||
applyLang(m.language, "", false);
|
||||
}
|
||||
}
|
||||
|
||||
function fill_items() {
|
||||
$tbody_message.empty();
|
||||
$tbody_broadcastzones.empty();
|
||||
const annIDSet = new Set();
|
||||
message_table.clear().draw();
|
||||
$select_broadcastzones.select2();
|
||||
|
||||
$select_airline.select2();
|
||||
$select_city.select2();
|
||||
@@ -691,118 +695,59 @@ function fill_items() {
|
||||
if (window.semiautodata !== null) {
|
||||
if (window.semiautodata.messages !== null && Array.isArray(window.semiautodata.messages) && window.semiautodata.messages.length > 0) {
|
||||
for (let msg of window.semiautodata.messages) {
|
||||
const txt = msg.description + " [" + msg.id + "]";
|
||||
|
||||
// check if tbody_message already has a row with the same text
|
||||
let exists = false;
|
||||
$("#tbody_message tr td").each(function () {
|
||||
if ($(this).text() === txt) {
|
||||
exists = true;
|
||||
}
|
||||
});
|
||||
if (!exists) {
|
||||
let $tr = $("<tr></tr>");
|
||||
let $td = $("<td></td>").text(txt);
|
||||
$tr.append($td);
|
||||
$tbody_message.append($tr);
|
||||
|
||||
$tr.css("cursor", "pointer");
|
||||
$tr.data("msgid", msg.id);
|
||||
|
||||
$tr.on("click", function (e) {
|
||||
const $row = $(this);
|
||||
const groupId = $row.data("msgid");
|
||||
const willSelect = !$row.hasClass("table-active");
|
||||
|
||||
// helper to map language string to preview & checkbox
|
||||
function applyLang(lang, value, checked) {
|
||||
const l = (lang || "").toString().trim().toLowerCase();
|
||||
if (l.startsWith("indonesia")) {
|
||||
if (checked) $preview_indonesia.text(value); else $preview_indonesia.empty();
|
||||
$enable_indonesia.prop("checked", !!checked);
|
||||
return true;
|
||||
}
|
||||
if (l.startsWith("english")) {
|
||||
if (checked) $preview_english.text(value); else $preview_english.empty();
|
||||
$enable_english.prop("checked", !!checked);
|
||||
return true;
|
||||
}
|
||||
if (l.startsWith("chinese")) {
|
||||
if (checked) $preview_chinese.text(value); else $preview_chinese.empty();
|
||||
$enable_chinese.prop("checked", !!checked);
|
||||
return true;
|
||||
}
|
||||
if (l.startsWith("japanese")) {
|
||||
if (checked) $preview_japanese.text(value); else $preview_japanese.empty();
|
||||
$enable_japanese.prop("checked", !!checked);
|
||||
return true;
|
||||
}
|
||||
if (l.startsWith("arabic")) {
|
||||
if (checked) $preview_arabic.text(value); else $preview_arabic.empty();
|
||||
$enable_arabic.prop("checked", !!checked);
|
||||
return true;
|
||||
}
|
||||
if (l.startsWith("local")) {
|
||||
if (checked) $preview_local.text(value); else $preview_local.empty();
|
||||
$enable_local.prop("checked", !!checked);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// helper to clear previews for a given group id
|
||||
function clearGroupPreviews(gid) {
|
||||
if (!window.semiautodata || !Array.isArray(window.semiautodata.messages)) return;
|
||||
const sameMsgs = window.semiautodata.messages.filter(m => Number(m.id) === Number(gid));
|
||||
for (let m of sameMsgs) {
|
||||
applyLang(m.language, "", false);
|
||||
}
|
||||
}
|
||||
|
||||
selected_messages = [];
|
||||
if (willSelect) {
|
||||
// unselect other selected rows and clear their previews
|
||||
$tbody_message.find("tr.table-active").each(function () {
|
||||
if (this === e.currentTarget) return;
|
||||
const $other = $(this);
|
||||
const otherId = $other.data("msgid");
|
||||
$other.removeClass("table-active");
|
||||
clearGroupPreviews(otherId);
|
||||
});
|
||||
|
||||
// select this row and apply its messages to previews
|
||||
$row.addClass("table-active");
|
||||
if (window.semiautodata && Array.isArray(window.semiautodata.messages)) {
|
||||
const sameMsgs = window.semiautodata.messages.filter(m => Number(m.id) === Number(groupId));
|
||||
for (let m of sameMsgs) {
|
||||
applyLang(m.language, m.message_details, true);
|
||||
selected_messages.push(m);
|
||||
}
|
||||
enable_disable_fields();
|
||||
update_all_previews();
|
||||
}
|
||||
} else {
|
||||
// deselect this row and clear its previews
|
||||
$row.removeClass("table-active");
|
||||
clearGroupPreviews(groupId);
|
||||
}
|
||||
// check if message_table already has a row with the same id
|
||||
if (annIDSet.has(msg.id)) continue;
|
||||
annIDSet.add(msg.id);
|
||||
message_table.row.add({ id: msg.id, description: msg.description });
|
||||
}
|
||||
// redraw the message table
|
||||
message_table.draw(true);
|
||||
message_table.on('click', 'tbody tr', function () {
|
||||
const $row = $(this);
|
||||
let data = message_table.row(this).data();
|
||||
const willSelect = !$row.hasClass("table-active");
|
||||
selected_messages = [];
|
||||
if (willSelect) {
|
||||
// unselect other selected rows and clear their previews
|
||||
message_table.$('tr.table-active').each(function () {
|
||||
if (this === $row[0]) return;
|
||||
const $other = $(this);
|
||||
const otherData = message_table.row(this).data();
|
||||
$other.removeClass("table-active");
|
||||
clearGroupPreviews(otherData.id);
|
||||
});
|
||||
// select this row and apply its messages to previews
|
||||
$row.addClass("table-active");
|
||||
if (window.semiautodata && Array.isArray(window.semiautodata.messages)) {
|
||||
const sameMsgs = window.semiautodata.messages.filter(m => Number(m.id) === Number(data.id));
|
||||
for (let m of sameMsgs) {
|
||||
applyLang(m.language, m.message_details, true);
|
||||
selected_messages.push(m);
|
||||
}
|
||||
enable_disable_fields();
|
||||
update_all_previews();
|
||||
}
|
||||
|
||||
} else {
|
||||
$row.removeClass("table-active");
|
||||
clearGroupPreviews(data.id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
if (window.semiautodata.broadcastzones !== null && Array.isArray(window.semiautodata.broadcastzones) && window.semiautodata.broadcastzones.length > 0) {
|
||||
for (let zone of window.semiautodata.broadcastzones) {
|
||||
{
|
||||
const uid = 'bz_' + Math.random().toString(36).slice(2, 9);
|
||||
let $tr = $("<tr></tr>");
|
||||
let $checkbox = $("<input>").attr({ type: "checkbox", id: uid, value: zone });
|
||||
let $label = $("<label></label>").attr("for", uid).text(zone);
|
||||
let $td = $("<td></td>").append($checkbox).append(" ").append($label);
|
||||
$tr.append($td);
|
||||
$tbody_broadcastzones.append($tr);
|
||||
}
|
||||
}
|
||||
$select_broadcastzones.select2({
|
||||
data: window.semiautodata.broadcastzones,
|
||||
placeholder: "Select broadcast zones",
|
||||
width: '100%',
|
||||
multiple: true
|
||||
});
|
||||
// $('#select_broadcastzones').on('change', function () {
|
||||
// console.log("Selected broadcast zones:", $select_broadcastzones.val());
|
||||
// });
|
||||
$select_broadcastzones.val(null).trigger("change");
|
||||
}
|
||||
if (window.semiautodata.airlines !== null && Array.isArray(window.semiautodata.airlines) && window.semiautodata.airlines.length > 0) {
|
||||
const airlinedata = window.semiautodata.airlines.map(a => ({ id: a.tag, text: a.value + " [" + a.tag + "]" }));
|
||||
@@ -927,19 +872,16 @@ function fill_items() {
|
||||
}
|
||||
|
||||
function send_broadcast_message() {
|
||||
console.log("send_broadcast_message");
|
||||
if ($("#send_broadcast").hasClass("btn-disable")) {
|
||||
alert("Cannot send broadcast message. Please complete all required fields.");
|
||||
return;
|
||||
}
|
||||
// get all checked broadcast zones from tbody_broadcastzones
|
||||
// get all checked broadcast zones from $select_broadcastzones
|
||||
let selected_zones = [];
|
||||
$tbody_broadcastzones.find("input[type='checkbox']").each(function () {
|
||||
const $checkbox = $(this);
|
||||
if ($checkbox.is(":checked")) {
|
||||
selected_zones.push($checkbox.val());
|
||||
}
|
||||
$select_broadcastzones.val().forEach(zone => {
|
||||
selected_zones.push(zone);
|
||||
});
|
||||
console.log("Selected zones:", selected_zones);
|
||||
|
||||
if (selected_zones.length === 0) {
|
||||
alert("Please select at least one broadcast zone.");
|
||||
@@ -967,7 +909,7 @@ function send_broadcast_message() {
|
||||
|
||||
let tags = [];
|
||||
let msg = selected_messages[0];
|
||||
tags.push("ANN_ID:"+msg.id);
|
||||
tags.push("ANN_ID:" + msg.id);
|
||||
if (msg.message_details.indexOf('[CITY]') !== -1) {
|
||||
let cities = $select_city.val();
|
||||
if (Array.isArray(cities) && cities.length > 0) {
|
||||
@@ -1011,7 +953,6 @@ function send_broadcast_message() {
|
||||
tags: tags.join(" "),
|
||||
broadcastzones: selected_zones.join(";")
|
||||
}
|
||||
console.log("Payload:", payload);
|
||||
fetchAPI("SemiAuto", "POST", {}, payload, (data) => {
|
||||
alert("Broadcast message sent successfully.");
|
||||
}, (error) => {
|
||||
@@ -1023,7 +964,7 @@ function send_broadcast_message() {
|
||||
|
||||
// App start here
|
||||
$(document).ready(function () {
|
||||
console.log("javascript loaded");
|
||||
console.log("index loaded");
|
||||
$preview_indonesia = $("#message_indonesia");
|
||||
$preview_english = $("#message_english");
|
||||
$preview_chinese = $("#message_chinese");
|
||||
@@ -1037,9 +978,18 @@ $(document).ready(function () {
|
||||
$enable_arabic = $("#checkbox_arabic");
|
||||
$enable_local = $("#checkbox_local");
|
||||
$tbody_message = $("#tbody_message");
|
||||
$tbody_broadcastzones = $("#tbody_broadcastzones");
|
||||
message_table = new DataTable('#message_table', {
|
||||
columns: [
|
||||
{ title: 'ID', data: 'id' },
|
||||
{ title: 'Description', data: 'description' }
|
||||
],
|
||||
data: [],
|
||||
pageLength: 25
|
||||
})
|
||||
$select_broadcastzones = $("#select_broadcastzones");
|
||||
$select_airline = $("#select_airline");
|
||||
$select_city = $("#select_city");
|
||||
|
||||
$select_places = $("#select_places");
|
||||
$select_shalat = $("#select_shalat");
|
||||
$select_reason = $("#select_reason");
|
||||
@@ -1070,5 +1020,15 @@ $(document).ready(function () {
|
||||
send_broadcast_message();
|
||||
});
|
||||
|
||||
$('#selectallzones').off("click").on("click", function () {
|
||||
$select_broadcastzones.find('option').prop('selected', true);
|
||||
$select_broadcastzones.trigger('change');
|
||||
});
|
||||
|
||||
$('#clearallzones').off("click").on("click", function () {
|
||||
$select_broadcastzones.find('option').prop('selected', false);
|
||||
$select_broadcastzones.trigger('change');
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
110503
html/semiauto/assets/js/datatables.js
Normal file
110503
html/semiauto/assets/js/datatables.js
Normal file
File diff suppressed because one or more lines are too long
67
html/semiauto/assets/js/log.js
Normal file
67
html/semiauto/assets/js/log.js
Normal file
@@ -0,0 +1,67 @@
|
||||
tblog = null;
|
||||
|
||||
function load_log_data(datevalue){
|
||||
// check if format yyyy-mm-dd, convert to dd-mm-yyyy
|
||||
if (/^\d{4}-\d{2}-\d{2}$/.test(datevalue)) {
|
||||
const parts = datevalue.split("-");
|
||||
if (parts.length === 3) {
|
||||
datevalue = parts[2] + "-" + parts[1] + "-" + parts[0];
|
||||
}
|
||||
}
|
||||
console.log("Loading log data for date:", datevalue);
|
||||
tblog.clear().draw();
|
||||
fetchAPI('Log/'+datevalue,'GET',{}, null,function(data){
|
||||
//console.log("Log data fetched:", data);
|
||||
if (data && Array.isArray(data) && data.length > 0){
|
||||
data.forEach(function(item, index){
|
||||
tblog.row.add({
|
||||
index: index + 1,
|
||||
date: item.datenya,
|
||||
time: item.timenya,
|
||||
source: item.machine,
|
||||
message: item.description
|
||||
})
|
||||
});
|
||||
tblog.draw();
|
||||
}
|
||||
},function(error){
|
||||
console.error("Error fetching log data:", error);
|
||||
});
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
console.log("Log.js is loaded");
|
||||
tblog = new DataTable('#logtable',{
|
||||
columns: [
|
||||
{title: 'Index', data: 'index'},
|
||||
{title: 'Date', data: 'date'},
|
||||
{title: 'Time', data: 'time'},
|
||||
{title: 'Source', data: 'source'},
|
||||
{title: 'Message', data: 'message'}
|
||||
],
|
||||
pageLength: 25,
|
||||
data: [],
|
||||
buttons: ['excel', 'pdf', 'print'],
|
||||
layout: {
|
||||
topStart: 'buttons',
|
||||
topEnd: 'search'
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
$('#reload_log').on('click', function(){
|
||||
// get value from date_log
|
||||
let datevalue = $('#date_log').val();
|
||||
load_log_data(datevalue);
|
||||
});
|
||||
|
||||
let today = new Date().toISOString().split('T')[0];
|
||||
|
||||
$('#date_log').val(today);
|
||||
load_log_data(today);
|
||||
|
||||
$('#date_log').on('change', function(){
|
||||
let datevalue = $(this).val();
|
||||
load_log_data(datevalue);
|
||||
});
|
||||
});
|
||||
@@ -20,6 +20,7 @@
|
||||
<link rel="stylesheet" href="assets/css/bss-overrides.css">
|
||||
<link rel="stylesheet" href="assets/css/all.min.css">
|
||||
<link rel="stylesheet" href="assets/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="assets/css/datatables.css">
|
||||
<link rel="stylesheet" href="assets/css/select2.min.css">
|
||||
<link rel="stylesheet" href="assets/css/style.css">
|
||||
</head>
|
||||
@@ -47,19 +48,13 @@
|
||||
<div class="card card-border scroll pad-left">
|
||||
<div class="card-body">
|
||||
<div class="table-responsive table-message table-hover table">
|
||||
<table class="table table-hover" id="table_message">
|
||||
<table class="table table-hover" id="message_table">
|
||||
<thead class="card-border">
|
||||
<tr>
|
||||
<th class="header-bg text-darkblue">List Of Message</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="tbody_message">
|
||||
<tr>
|
||||
<td>Message 1 </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Message 2 </td>
|
||||
</tr>
|
||||
<tr></tr>
|
||||
<tr></tr>
|
||||
</tbody>
|
||||
@@ -72,30 +67,14 @@
|
||||
<div class="card border-0">
|
||||
<div class="card-header header-broadcast header-bg" style="font-family: Poppins, sans-serif;">
|
||||
<div class="row py-1">
|
||||
<div class="col-8 col-sm-9 col-md-9 col-lg-9 col-xl-9">
|
||||
<div class="col">
|
||||
<p class="pad-text-input"><strong>Broadcast Zones</strong></p>
|
||||
</div>
|
||||
<div class="col-4 col-sm-3 col-md-3 col-lg-3 col-xl-3">
|
||||
<div class="form-check pad-text-input"><input class="form-check-input" type="checkbox" data-bs-toggle="tooltip" data-bss-tooltip="" id="selectall_broadcast" title="Select All"><label class="form-check-label" for="selectall_broadcast-1"><strong>Select All</strong></label></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body div-broadcast">
|
||||
<div class="table-responsive table-message table">
|
||||
<table class="table table-hover" id="table_message">
|
||||
<thead>
|
||||
<tr></tr>
|
||||
</thead>
|
||||
<tbody id="tbody_broadcastzones">
|
||||
<tr>
|
||||
<td>
|
||||
<div class="form-check"><input class="form-check-input" type="checkbox" id="formCheck-16"><label class="form-check-label" for="formCheck-16">Domestic Arrival</label></div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="col-4 col-sm-3 col-md-3 col-lg-3 col-xl-3"><button class="btn w-100 pad-input btn-selectall" id="selectallzones" type="button" style="font-family: Raleway, sans-serif;">Select All</button></div>
|
||||
<div class="col-4 col-sm-3 col-md-3 col-lg-3 col-xl-3"><button class="btn w-100 pad-input btn-deselectall" id="clearallzones" type="button" style="font-family: Raleway, sans-serif;">Deselect All</button></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body div-broadcast"><select class="w-100 h-100" id="select_broadcastzones"></select></div>
|
||||
</div>
|
||||
<div class="row mt-2 py-3">
|
||||
<div class="col"><label class="form-label pad-flight"><strong> Flight Information</strong></label>
|
||||
@@ -239,11 +218,12 @@
|
||||
<footer></footer>
|
||||
<script src="assets/js/jquery.min.js"></script>
|
||||
<script src="assets/bootstrap/js/bootstrap.min.js"></script>
|
||||
<script src="assets/js/bs-init.js"></script>
|
||||
<script src="assets/js/custom.js"></script>
|
||||
<script src="assets/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="assets/js/datatables.js"></script>
|
||||
<script src="assets/js/jquery-3.7.1.min.js"></script>
|
||||
<script src="assets/js/select2.min.js"></script>
|
||||
<script src="assets/js/common.js"></script>
|
||||
<script src="assets/js/custom.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -20,6 +20,7 @@
|
||||
<link rel="stylesheet" href="assets/css/bss-overrides.css">
|
||||
<link rel="stylesheet" href="assets/css/all.min.css">
|
||||
<link rel="stylesheet" href="assets/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="assets/css/datatables.css">
|
||||
<link rel="stylesheet" href="assets/css/select2.min.css">
|
||||
<link rel="stylesheet" href="assets/css/style.css">
|
||||
</head>
|
||||
@@ -50,15 +51,10 @@
|
||||
<path d="M19.933 13.041a8 8 0 1 1 -9.925 -8.788c3.899 -1 7.935 1.007 9.425 4.747"></path>
|
||||
<path d="M20 4v5h-5"></path>
|
||||
</svg> Reload</button></div>
|
||||
<div class="col-6 col-sm-6 col-md-2 col-lg-2 col-xl-1 col-xxl-1 pad-reload"><button class="btn btn-primary w-100 pad-input" id="export_log" type="button" style="font-family: Raleway, sans-serif;"><svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icon-tabler-file-export pad-icon" id="export_log">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<path d="M14 3v4a1 1 0 0 0 1 1h4"></path>
|
||||
<path d="M11.5 21h-4.5a2 2 0 0 1 -2 -2v-14a2 2 0 0 1 2 -2h7l5 5v5m-5 6h7m-3 -3l3 3l-3 3"></path>
|
||||
</svg> Export</button></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-100 container-fluid">
|
||||
<div class="table-responsive table custom-striped">
|
||||
<div class="table-responsive table custom-striped" id="tablelog">
|
||||
<table class="table table-striped" id="logtable" data-sortable="true" data-toggle="table" data-pagination="true">
|
||||
<thead class="bg-header-table table-fixed">
|
||||
<tr class="w-100 bg-header-table">
|
||||
@@ -98,11 +94,12 @@
|
||||
</section>
|
||||
<script src="assets/js/jquery.min.js"></script>
|
||||
<script src="assets/bootstrap/js/bootstrap.min.js"></script>
|
||||
<script src="assets/js/bs-init.js"></script>
|
||||
<script src="assets/js/custom.js"></script>
|
||||
<script src="assets/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="assets/js/datatables.js"></script>
|
||||
<script src="assets/js/jquery-3.7.1.min.js"></script>
|
||||
<script src="assets/js/select2.min.js"></script>
|
||||
<script src="assets/js/common.js"></script>
|
||||
<script src="assets/js/log.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -20,6 +20,7 @@
|
||||
<link rel="stylesheet" href="assets/css/bss-overrides.css">
|
||||
<link rel="stylesheet" href="assets/css/all.min.css">
|
||||
<link rel="stylesheet" href="assets/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="assets/css/datatables.css">
|
||||
<link rel="stylesheet" href="assets/css/select2.min.css">
|
||||
<link rel="stylesheet" href="assets/css/style.css">
|
||||
</head>
|
||||
@@ -60,11 +61,11 @@
|
||||
</section>
|
||||
<script src="assets/js/jquery.min.js"></script>
|
||||
<script src="assets/bootstrap/js/bootstrap.min.js"></script>
|
||||
<script src="assets/js/bs-init.js"></script>
|
||||
<script src="assets/js/custom.js"></script>
|
||||
<script src="assets/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="assets/js/datatables.js"></script>
|
||||
<script src="assets/js/jquery-3.7.1.min.js"></script>
|
||||
<script src="assets/js/select2.min.js"></script>
|
||||
<script src="assets/js/common.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -113,6 +113,17 @@ $(document).ready(function () {
|
||||
// for adding selected item from messageavailablevariables to messageselectedvariables
|
||||
let $btnaddtolist = $modal.find('#btnaddtolist');
|
||||
|
||||
/**
|
||||
* Create <option> element
|
||||
* @param {string} value value assigned to this <option>
|
||||
* @param {string} text text assigned to this <option>
|
||||
* @param {string} title text displayed when mouse hover on this <option>
|
||||
* @returns {JQuery<HTMLOptionElement>} jQuery object representing the created <option> element
|
||||
*/
|
||||
function create_option(value, text, title) {
|
||||
return $('<option>', { value: value, text: text, title: title });
|
||||
}
|
||||
|
||||
/**
|
||||
* Refill messageavailablevariables options from categories[]
|
||||
* and soundbankdata with category "Phrase" if messagelanguage and messagevoicetype are selected
|
||||
@@ -125,12 +136,11 @@ $(document).ready(function () {
|
||||
if ("Airline_Code" === cat) cat = "Flight_Number"; // revisi 15012026 karena inconsistensi penamaan tag
|
||||
if ("Gate" === cat) cat = "GateNumber"; // revisi 03202026 karena inconsistensi penamaan tag
|
||||
let displayCat = `[${cat}]`.toUpperCase();
|
||||
$messageavailablevariables.append(new Option(text = displayCat, value = displayCat, title = displayCat));
|
||||
$messageavailablevariables.append(create_option(displayCat, displayCat, displayCat));
|
||||
});
|
||||
// tambah [ETAD], [BCB] revisi 19012026
|
||||
$messageavailablevariables.append(new Option(text = '[ETAD]', value = '[ETAD]', title = '[ETAD]'));
|
||||
$messageavailablevariables.append(new Option(text = '[BCB]', value = '[BCB]', title = '[BCB]'));
|
||||
|
||||
$messageavailablevariables.append(create_option('[ETAD]', '[ETAD]', '[ETAD]'));
|
||||
$messageavailablevariables.append(create_option('[BCB]', '[BCB]', '[BCB]'));
|
||||
let lang = $messagelanguage.val();
|
||||
let vt = $messagevoicetype.val();
|
||||
if (lang && lang.length > 0 && vt && vt.length > 0) {
|
||||
@@ -143,7 +153,7 @@ $(document).ready(function () {
|
||||
let v1 = sb.tag.toUpperCase();
|
||||
let t1 = sb.description + ` [${v1}]`;
|
||||
let t2 = sb.description;
|
||||
$messageavailablevariables.append($('<option>', { value: v1, text: t1, title: t2 }));
|
||||
$messageavailablevariables.append(create_option(v1, t1, t2));
|
||||
}
|
||||
});
|
||||
if (cbLoaded && typeof cbLoaded === 'function') {
|
||||
@@ -224,7 +234,7 @@ $(document).ready(function () {
|
||||
Message_Detail: messagedetail,
|
||||
Message_TAGS: messagetags
|
||||
};
|
||||
console.log("Constructed MessageBank object:", JSON.stringify(mb));
|
||||
console.log("Constructed MessageBank object:", mb);
|
||||
return mb;
|
||||
}
|
||||
|
||||
|
||||
@@ -273,6 +273,15 @@ function DoClear(APIURL, whattoclear, cbOK, cbError) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a string is valid (not null, is string, not empty after trim)
|
||||
* @param {string} str
|
||||
* @returns true if valid, false otherwise
|
||||
*/
|
||||
function ValidString(str){
|
||||
if (str && typeof str === 'string' && str.trim().length>0) return true; else return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Export mechanism to XLSX file
|
||||
@@ -377,10 +386,11 @@ $(document).ready(function () {
|
||||
function resetStatusIndicators() {
|
||||
$('#onlineindicator').attr('src', window.redcircle);
|
||||
$('#cpustatus').text("CPU : N/A");
|
||||
$('#ramstatus').text("RAM : N/A");
|
||||
$('#diskstatus').text("Disk : N/A");
|
||||
$('#appversion').text("Version : N/A");
|
||||
$('#networkstatus').text("Network : N/A");
|
||||
$('#datetimetext').text("Date/Time : N/A");
|
||||
$('#systemtime').text("System Time : N/A");
|
||||
$('#appuptime').text("App Uptime : N/A");
|
||||
$('#osuptime').text("OS Uptime : N/A");
|
||||
}
|
||||
|
||||
|
||||
@@ -402,6 +412,7 @@ $(document).ready(function () {
|
||||
s.addEventListener('open', () => {
|
||||
//console.log('WebSocket connection established');
|
||||
$('#onlineindicator').attr('src', window.greencircle);
|
||||
sendCommand("getAppVersion", "");
|
||||
|
||||
if (ws_reconnect) {
|
||||
// stop reconnect attempts
|
||||
@@ -430,14 +441,27 @@ $(document).ready(function () {
|
||||
let data = rep.data;
|
||||
if (cmd && cmd.length > 0) {
|
||||
switch (cmd) {
|
||||
case "getAppVersion":
|
||||
$('#appversion').text("Version : " + data)
|
||||
break;
|
||||
case "getCPUStatus":
|
||||
$('#cpustatus').text("CPU : " + data)
|
||||
break;
|
||||
case "getMemoryStatus":
|
||||
$('#ramstatus').text("RAM : " + data)
|
||||
let ramjson = JSON.parse(data);
|
||||
//console.log("ram json", ramjson)
|
||||
$('#ramtotal').text("Total : " + (ValidString(ramjson.Total)?ramjson.Total:"N/A"));
|
||||
$('#ramused').text("Used : " + (ValidString(ramjson.Used)?ramjson.Used:"N/A"));
|
||||
$('#ramavailable').text("Free : " + (ValidString(ramjson.Available)?ramjson.Available:"N/A"));
|
||||
$('#rampercent').text("Usage : " + (ValidString(ramjson.Usage)?ramjson.Usage:"N/A"));
|
||||
break;
|
||||
case "getDiskStatus":
|
||||
$('#diskstatus').text("Disk : " + data)
|
||||
let diskjson = JSON.parse(data);
|
||||
//console.log("disk json", diskjson)
|
||||
$('#disktotal').text("Total : " + (ValidString(diskjson.Total)?diskjson.Total:"N/A"));
|
||||
$('#diskused').text("Used : " + (ValidString(diskjson.Used)?diskjson.Used:"N/A"));
|
||||
$('#diskavailable').text("Free : " + (ValidString(diskjson.Available)?diskjson.Available:"N/A"));
|
||||
$('#diskpercent').text("Usage : " + (ValidString(diskjson.Usage)?diskjson.Usage:"N/A"));
|
||||
break;
|
||||
case "getNetworkStatus":
|
||||
let result = "";
|
||||
@@ -458,7 +482,10 @@ $(document).ready(function () {
|
||||
$('#networkstatus').text(result)
|
||||
break;
|
||||
case "getSystemTime":
|
||||
$('#datetimetext').text(data)
|
||||
let timejson = JSON.parse(data);
|
||||
$('#systemtime').text("System Time : " + (ValidString(timejson.systemtime)?timejson.systemtime:"N/A"));
|
||||
$('#appuptime').text("App Uptime : " + (ValidString(timejson.apptime)?timejson.apptime:"N/A"));
|
||||
$('#osuptime').text("OS Uptime : " + (ValidString(timejson.uptime)?timejson.uptime:"N/A"));
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
@@ -99,19 +99,60 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col card-status">
|
||||
<p class="w-100 h-100 text-status" id="cpustatus">CPU Status : <br><br></p>
|
||||
<div class="row">
|
||||
<p id="cpustatus">CPU : N/A</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p id="appversion">Version : N/A</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col card-status">
|
||||
<p class="w-100 h-100 text-status" id="ramstatus">RAM Status : <br><br></p>
|
||||
<div class="row">
|
||||
<p>RAM Status</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p id="ramtotal">Total : N/A</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p id="ramused">Used : N/A</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p id="ramavailable">Available : N/A</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p id="rampercent">Used : N/A</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col card-status">
|
||||
<p class="w-100 h-100 text-status" id="diskstatus">Disk Status : <br><br></p>
|
||||
<div class="row">
|
||||
<p>Disk Status</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p id="disktotal">Total : N/A</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p id="diskused">Used : N/A</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p id="diskavailable">Available : N/A</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p id="diskpercent">Used : N/A</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col card-status">
|
||||
<p class="w-100 h-100 text-status" id="networkstatus">Network </p>
|
||||
</div>
|
||||
<div class="col card-status">
|
||||
<p class="w-100 h-100 text-status" id="datetimetext">Date and Time </p>
|
||||
<div class="row">
|
||||
<p id="systemtime">System Time : N/A</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p id="appuptime">App Uptime : N/A</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p id="osuptime">OS Uptime : N/A</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container w-100 pad-container" id="content"></div>
|
||||
|
||||
@@ -59,19 +59,60 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col card-status">
|
||||
<p class="w-100 h-100 text-status" id="cpustatus">CPU Status : <br><br></p>
|
||||
<div class="row">
|
||||
<p id="cpustatus">CPU : N/A</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p id="appversion">Version : N/A</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col card-status">
|
||||
<p class="w-100 h-100 text-status" id="ramstatus">RAM Status : <br><br></p>
|
||||
<div class="row">
|
||||
<p>RAM Status</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p id="ramtotal">Total : N/A</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p id="ramused">Used : N/A</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p id="ramavailable">Available : N/A</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p id="rampercent">Used : N/A</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col card-status">
|
||||
<p class="w-100 h-100 text-status" id="diskstatus">Disk Status : <br><br></p>
|
||||
<div class="row">
|
||||
<p>Disk Status</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p id="disktotal">Total : N/A</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p id="diskused">Used : N/A</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p id="diskavailable">Available : N/A</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p id="diskpercent">Used : N/A</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col card-status">
|
||||
<p class="w-100 h-100 text-status" id="networkstatus">Network </p>
|
||||
</div>
|
||||
<div class="col card-status">
|
||||
<p class="w-100 h-100 text-status" id="datetimetext">Date and Time </p>
|
||||
<div class="row">
|
||||
<p id="systemtime">System Time : N/A</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p id="appuptime">App Uptime : N/A</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p id="osuptime">OS Uptime : N/A</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container w-100 pad-container" id="content"></div>
|
||||
|
||||
@@ -39,10 +39,11 @@ lateinit var audioPlayer: AudioPlayer
|
||||
val StreamerOutputs: MutableMap<String, BarixConnection> = HashMap()
|
||||
lateinit var udpreceiver: UDPReceiver
|
||||
lateinit var tcpreceiver: TCPReceiver
|
||||
const val version = "0.0.27 (03/02/2026)"
|
||||
const val version = "0.0.28 (04/02/2026)"
|
||||
// AAS 64 channels
|
||||
const val max_channel = 64
|
||||
|
||||
val apptick : Long = System.currentTimeMillis()
|
||||
// dipakai untuk ambil messagebank berdasarkan id
|
||||
val urutan_bahasa = listOf(
|
||||
Language.INDONESIA.name,
|
||||
|
||||
@@ -132,11 +132,11 @@ class BarixConnection(val index: UInt, var channel: String, val ipaddress: Strin
|
||||
val chunk = ByteArray(if (bb.remaining() > maxUDPsize) maxUDPsize else bb.remaining())
|
||||
bb.get(chunk)
|
||||
while(bufferRemain<chunk.size){
|
||||
delay(10)
|
||||
delay(5)
|
||||
}
|
||||
udp.send(DatagramPacket(chunk, chunk.size, inet))
|
||||
mp3encoder.PushData(chunk)
|
||||
delay(2)
|
||||
delay(1)
|
||||
|
||||
|
||||
} catch (e: Exception) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package codes
|
||||
|
||||
import apptick
|
||||
import com.fasterxml.jackson.databind.JsonNode
|
||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||
import content.Category
|
||||
@@ -378,7 +379,7 @@ class Somecodes {
|
||||
* @param path The path to check disk usage, defaults to the current working directory.
|
||||
* @return A string representing the disk usage of the file system in a human-readable format.
|
||||
*/
|
||||
fun getDiskUsage(path: String = current_directory) : String {
|
||||
fun getDiskUsageString(path: String = current_directory) : String {
|
||||
return try{
|
||||
val p = Path.of(path).toFile()
|
||||
if (p.exists() && p.isDirectory){
|
||||
@@ -398,6 +399,26 @@ class Somecodes {
|
||||
}
|
||||
}
|
||||
|
||||
fun getDiskUsage(path: String = current_directory) : Map<String, String> {
|
||||
return try{
|
||||
val p = Path.of(path).toFile()
|
||||
if (p.exists() && p.isDirectory){
|
||||
val total = p.totalSpace
|
||||
val free = p.freeSpace
|
||||
val used = total - free
|
||||
mapOf(
|
||||
"Total" to SizetoHuman(total),
|
||||
"Used" to SizetoHuman(used),
|
||||
"Available" to SizetoHuman(free),
|
||||
"Usage" to String.format("%.2f%%", (used.toDouble() / total * 100))
|
||||
)
|
||||
} else throw Exception()
|
||||
|
||||
} catch (_ : Exception){
|
||||
emptyMap()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get CPU usage using OSHI library.
|
||||
* @param cb A callback function that receives the CPU usage as a string.
|
||||
@@ -430,7 +451,7 @@ class Somecodes {
|
||||
* Get RAM usage using OSHI library.
|
||||
* @return A string representing the total, used, and available memory in a human-readable format.
|
||||
*/
|
||||
fun getMemoryUsage() : String{
|
||||
fun getMemoryUsageString() : String{
|
||||
val totalMemory = memory.total
|
||||
val availableMemory = memory.available
|
||||
val usedMemory = totalMemory - availableMemory
|
||||
@@ -441,6 +462,18 @@ class Somecodes {
|
||||
, (usedMemory.toDouble() / totalMemory * 100))
|
||||
}
|
||||
|
||||
fun getMemoryUsage() : Map<String, String> {
|
||||
val totalMemory = memory.total
|
||||
val availableMemory = memory.available
|
||||
val usedMemory = totalMemory - availableMemory
|
||||
return mapOf(
|
||||
"Total" to SizetoHuman(totalMemory),
|
||||
"Used" to SizetoHuman(usedMemory),
|
||||
"Available" to SizetoHuman(availableMemory),
|
||||
"Usage" to String.format("%.2f%%", (usedMemory.toDouble() / totalMemory * 100))
|
||||
)
|
||||
}
|
||||
|
||||
fun GetNetworkStatus(cb : Consumer<List<NetworkInformation>>) {
|
||||
val networks: List<NetworkIF> = si.hardware.networkIFs.toList()
|
||||
networks.forEach { net ->
|
||||
@@ -706,6 +739,10 @@ class Somecodes {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get OS uptime using OSHI library.
|
||||
* @return A string representing the OS uptime in the format "HH:mm:ss", or an empty string if not available.
|
||||
*/
|
||||
fun GetUptime() : String {
|
||||
val value = os.systemUptime
|
||||
return if (value>0){
|
||||
@@ -717,6 +754,19 @@ class Somecodes {
|
||||
} else ""
|
||||
}
|
||||
|
||||
/**
|
||||
* Get application uptime.
|
||||
* @return A string representing the application uptime in the format "HH:mm:ss".
|
||||
*/
|
||||
fun GetAppUpTime() : String {
|
||||
val uptimeMillis = System.currentTimeMillis() - apptick
|
||||
val totalSeconds = uptimeMillis / 1000
|
||||
val hours = totalSeconds / 3600
|
||||
val minutes = (totalSeconds % 3600) / 60
|
||||
val seconds = totalSeconds % 60
|
||||
return String.format("%02d:%02d:%02d", hours, minutes, seconds)
|
||||
}
|
||||
|
||||
fun Generate_WAV_Header() : ByteArray {
|
||||
val sampleRate = 44100
|
||||
val bitsPerSample = 16
|
||||
|
||||
@@ -3,6 +3,7 @@ package web
|
||||
import StreamerOutputs
|
||||
import barix.BarixConnection
|
||||
import codes.Somecodes
|
||||
import codes.Somecodes.Companion.GetAppUpTime
|
||||
import codes.Somecodes.Companion.GetSensorsInfo
|
||||
import codes.Somecodes.Companion.GetUptime
|
||||
import codes.Somecodes.Companion.ListAudioFiles
|
||||
@@ -49,6 +50,7 @@ import google.autoadd
|
||||
import google.fileoperation
|
||||
import io.javalin.websocket.WsCloseStatus
|
||||
import org.tinylog.Logger
|
||||
import version
|
||||
import java.io.File
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.file.Path
|
||||
@@ -147,13 +149,26 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
|
||||
val cmd =
|
||||
objectmapper.readValue(wsMessageContext.message(), WebsocketCommand::class.java)
|
||||
when (cmd.command) {
|
||||
"getAppVersion" ->{
|
||||
SendReply(wsMessageContext, cmd.command, version)
|
||||
}
|
||||
"getSystemTime" -> {
|
||||
|
||||
val systemtime = LocalDateTime.now().format(datetimeformat1)
|
||||
val uptime = GetUptime()
|
||||
val apptime = GetAppUpTime()
|
||||
// create JSON object of systemtime, uptime and apptime
|
||||
val timejson = objectmapper.writeValueAsString(
|
||||
mapOf(
|
||||
"systemtime" to systemtime,
|
||||
"uptime" to uptime,
|
||||
"apptime" to apptime
|
||||
)
|
||||
)
|
||||
SendReply(
|
||||
wsMessageContext,
|
||||
cmd.command,
|
||||
if (uptime.isNotEmpty()) "Date & Time : $systemtime\nSystem Uptime : $uptime" else "Date & Time : $systemtime"
|
||||
timejson
|
||||
)
|
||||
}
|
||||
|
||||
@@ -169,11 +184,11 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
|
||||
}
|
||||
|
||||
"getMemoryStatus" -> {
|
||||
SendReply(wsMessageContext, cmd.command, Somecodes.getMemoryUsage())
|
||||
SendReply(wsMessageContext, cmd.command, objectmapper.writeValueAsString(Somecodes.getMemoryUsage()))
|
||||
}
|
||||
|
||||
"getDiskStatus" -> {
|
||||
SendReply(wsMessageContext, cmd.command, Somecodes.getDiskUsage())
|
||||
SendReply(wsMessageContext, cmd.command, objectmapper.writeValueAsString(Somecodes.getDiskUsage()))
|
||||
}
|
||||
|
||||
"getNetworkStatus" -> {
|
||||
@@ -267,10 +282,20 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
|
||||
"getSystemTime" -> {
|
||||
val systemtime = LocalDateTime.now().format(datetimeformat1)
|
||||
val uptime = GetUptime()
|
||||
val apptime = GetAppUpTime()
|
||||
// create JSON object of systemtime, uptime and apptime
|
||||
val timejson = objectmapper.writeValueAsString(
|
||||
mapOf(
|
||||
"systemtime" to systemtime,
|
||||
"uptime" to uptime,
|
||||
"apptime" to apptime
|
||||
)
|
||||
)
|
||||
|
||||
SendReply(
|
||||
wsMessageContext,
|
||||
cmd.command,
|
||||
if (uptime.isNotEmpty()) "Date & Time : $systemtime\nSystem Uptime : $uptime" else "Date & Time : $systemtime"
|
||||
timejson
|
||||
)
|
||||
}
|
||||
|
||||
@@ -286,11 +311,11 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
|
||||
}
|
||||
|
||||
"getMemoryStatus" -> {
|
||||
SendReply(wsMessageContext, cmd.command, Somecodes.getMemoryUsage())
|
||||
SendReply(wsMessageContext, cmd.command, objectmapper.writeValueAsString(Somecodes.getMemoryUsage()))
|
||||
}
|
||||
|
||||
"getDiskStatus" -> {
|
||||
SendReply(wsMessageContext, cmd.command, Somecodes.getDiskUsage())
|
||||
SendReply(wsMessageContext, cmd.command, objectmapper.writeValueAsString(Somecodes.getDiskUsage()))
|
||||
}
|
||||
|
||||
"getNetworkStatus" -> {
|
||||
@@ -1399,9 +1424,15 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
|
||||
val atags = airline_tags.split(";").map { it.trim() }
|
||||
.filter { it.isNotEmpty() }.distinct()
|
||||
val airlinetags = db.Get_AirlineCode_Tags()
|
||||
if (!atags.all { tag -> airlinetags.any { it.equals(tag,true) } }) {
|
||||
val missing_airlinetags = ArrayList<String>()
|
||||
atags.forEach { tag ->
|
||||
if (!airlinetags.any { it.equals(tag,true) }) {
|
||||
missing_airlinetags.add(tag)
|
||||
}
|
||||
}
|
||||
if (missing_airlinetags.isNotEmpty()){
|
||||
ctx.status(400)
|
||||
.result(objectmapper.writeValueAsString(resultMessage("Some airline tags not found in soundbank")))
|
||||
.result(objectmapper.writeValueAsString(resultMessage("Airline tags not found in soundbank: ${missing_airlinetags.joinToString(", ")}")))
|
||||
return@post
|
||||
}
|
||||
}
|
||||
@@ -1411,11 +1442,18 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
|
||||
val ctags = city_tags.split(";").map { it.trim() }
|
||||
.filter { it.isNotEmpty() }.distinct()
|
||||
val citytags = db.Get_City_Tags()
|
||||
if (!ctags.all { tag -> citytags.any { it.equals(tag,true) } }) {
|
||||
val missing_citytags = ArrayList<String>()
|
||||
ctags.forEach { tag ->
|
||||
if (!citytags.any { it.equals(tag,true) }) {
|
||||
missing_citytags.add(tag)
|
||||
}
|
||||
}
|
||||
if (missing_citytags.isNotEmpty()){
|
||||
ctx.status(400)
|
||||
.result(objectmapper.writeValueAsString(resultMessage("Some city tags not found in soundbank")))
|
||||
.result(objectmapper.writeValueAsString(resultMessage("City tags not found in soundbank: ${missing_citytags.joinToString(", ")}")))
|
||||
return@post
|
||||
}
|
||||
|
||||
}
|
||||
if (ValidString(messagebank_ann_id)){
|
||||
// ada messagebank_ann_id, berarti harus di cek apakah ada di table messagebank
|
||||
@@ -1437,12 +1475,19 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
|
||||
broadcastzones.split(";").map { it.trim() }
|
||||
.filter { it.isNotEmpty() }.distinct()
|
||||
val bzlist = db.Get_BroadcastZone_List()
|
||||
if (!bzdesc.all { desc -> bzlist.any { it.equals(desc,true) } }) {
|
||||
val missing_broadcastzones = ArrayList<String>()
|
||||
bzdesc.forEach { bz ->
|
||||
if (!bzlist.any { it.equals(bz,true) }) {
|
||||
missing_broadcastzones.add(bz)
|
||||
}
|
||||
}
|
||||
if (missing_broadcastzones.isNotEmpty()){
|
||||
ctx.status(400)
|
||||
.result(objectmapper.writeValueAsString(resultMessage("Some broadcast zone tags not found in soundbank")))
|
||||
.result(objectmapper.writeValueAsString(resultMessage("Broadcast zone tags not found in soundbank: ${missing_broadcastzones.joinToString(", ")}")))
|
||||
return@post
|
||||
}
|
||||
|
||||
|
||||
// sampe sini valid semua
|
||||
// semua valid, tambain ke database
|
||||
val newuser = UserDB(
|
||||
@@ -1524,11 +1569,18 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
|
||||
val atags = _airline_tags.split(";").map { it.trim() }
|
||||
.filter { it.isNotEmpty() }.distinct()
|
||||
val airlinetags = db.Get_AirlineCode_Tags()
|
||||
if (!atags.all { tag -> airlinetags.any { it.equals(tag,true) } }) {
|
||||
val missing_airlinetags = ArrayList<String>()
|
||||
atags.forEach { tag ->
|
||||
if (!airlinetags.any { it.equals(tag,true) }) {
|
||||
missing_airlinetags.add(tag)
|
||||
}
|
||||
}
|
||||
if (missing_airlinetags.isNotEmpty()){
|
||||
ctx.status(400)
|
||||
.result(objectmapper.writeValueAsString(resultMessage("Some airline tags not found in soundbank")))
|
||||
.result(objectmapper.writeValueAsString(resultMessage("Airline tags not found in soundbank: ${missing_airlinetags.joinToString(", ")}")))
|
||||
return@patch
|
||||
}
|
||||
|
||||
}
|
||||
if (ValidString(_city_tags)){
|
||||
// ada city_tags, berarti harus di cek apakah ada di table soundbank
|
||||
@@ -1536,11 +1588,17 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
|
||||
val ctags = _city_tags.split(";").map { it.trim() }
|
||||
.filter { it.isNotEmpty() }.distinct()
|
||||
val citytags = db.Get_City_Tags()
|
||||
if (!ctags.all { tag -> citytags.any { it.equals(tag,true) } }) {
|
||||
ctx.status(400)
|
||||
.result(objectmapper.writeValueAsString(resultMessage("Some city tags not found in soundbank")))
|
||||
val missing_citytags = ArrayList<String>()
|
||||
ctags.forEach { tag ->
|
||||
if (!citytags.any { it.equals(tag,true) }) {
|
||||
missing_citytags.add(tag)
|
||||
}
|
||||
}
|
||||
if (missing_citytags.isNotEmpty()){ ctx.status(400)
|
||||
.result(objectmapper.writeValueAsString(resultMessage("City tags not found in soundbank: ${missing_citytags.joinToString(", ")}")))
|
||||
return@patch
|
||||
}
|
||||
|
||||
}
|
||||
if (ValidString(_messagebank_ann_id)){
|
||||
// ada messagebank_ann_id, berarti harus di cek apakah ada di table messagebank
|
||||
@@ -1550,22 +1608,36 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
|
||||
.filter { it.isNotEmpty() }.distinct()
|
||||
.mapNotNull { it.toUIntOrNull() }
|
||||
val mbankids = db.Get_MessageID_List()
|
||||
if (!mbids.all { id -> mbankids.any { it == id } }) {
|
||||
val missing_broadcastids = ArrayList<UInt>()
|
||||
mbids.forEach { mbid ->
|
||||
if (!mbankids.any { it == mbid }) {
|
||||
missing_broadcastids.add(mbid)
|
||||
}
|
||||
}
|
||||
if (missing_broadcastids.isNotEmpty()){
|
||||
ctx.status(400)
|
||||
.result(objectmapper.writeValueAsString(resultMessage("Some ANN_ID not found in Messagebank")))
|
||||
.result(objectmapper.writeValueAsString(resultMessage("ANN_ID not found in Messagebank: ${missing_broadcastids.joinToString(", ")}")))
|
||||
return@patch
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
val bzdesc = _broadcastzones.split(";").map { it.trim() }
|
||||
.filter { it.isNotEmpty() }.distinct()
|
||||
val bzlist = db.Get_BroadcastZone_List()
|
||||
if (!bzdesc.all { desc -> bzlist.any { it.equals(desc,true) } }) {
|
||||
val missing_broadcastzones = ArrayList<String>()
|
||||
bzdesc.forEach { bz ->
|
||||
if (!bzlist.any { it.equals(bz,true) }) {
|
||||
missing_broadcastzones.add(bz)
|
||||
}
|
||||
}
|
||||
if (missing_broadcastzones.isNotEmpty()){
|
||||
ctx.status(400)
|
||||
.result(objectmapper.writeValueAsString(resultMessage("Some broadcast zone is not found in Broadcast Zone list")))
|
||||
.result(objectmapper.writeValueAsString(resultMessage("Broadcast zone tags not found in soundbank: ${missing_broadcastzones.joinToString(", ")}")))
|
||||
return@patch
|
||||
}
|
||||
|
||||
|
||||
// sampe sini valid semua
|
||||
val editeduser = UserDB(
|
||||
index,
|
||||
@@ -2442,6 +2514,7 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
|
||||
before { CheckSemiAutoUsers(it) }
|
||||
}
|
||||
path("api") {
|
||||
|
||||
path("Initialize") {
|
||||
get { ctx ->
|
||||
val username = ctx.cookie("semiauto-user") ?: ""
|
||||
@@ -2451,7 +2524,9 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
|
||||
val result = SemiAutoInitData(username)
|
||||
// messages
|
||||
String_To_List(user.messagebank_ann_id).forEach { msg ->
|
||||
//println("Looking for message ANN_ID: $msg")
|
||||
db.messageDB.List.filter { it.ANN_ID == msg.toUInt() }.forEach { xx ->
|
||||
//println("Adding message: ${xx.ANN_ID};${xx.Description};${xx.Language};${xx.Message_Detail}")
|
||||
result.messages.add("${xx.ANN_ID};${xx.Description};${xx.Language};${xx.Message_Detail}")
|
||||
}
|
||||
}
|
||||
@@ -2552,10 +2627,36 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
|
||||
|
||||
}
|
||||
}
|
||||
get("ExportXLSX") { get1 ->
|
||||
val logdate = get1.queryParam("date") ?: ""
|
||||
val logfilter = get1.queryParam("filter") ?: ""
|
||||
if (ValiDateForLogHtml(logdate)) {
|
||||
val xlsxdata = if (ValidString(logfilter)) {
|
||||
db.Export_Log_XLSX(logdate.replace('-', '/'), logfilter)
|
||||
} else {
|
||||
db.Export_Log_XLSX(logdate.replace('-', '/'), "")
|
||||
}
|
||||
if (xlsxdata != null) {
|
||||
get1.header(
|
||||
"Content-Type",
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
||||
)
|
||||
get1.header("Content-Disposition", "attachment; filename=\"log_$logdate.xlsx\"")
|
||||
get1.outputStream().use { out ->
|
||||
xlsxdata.write(out)
|
||||
}
|
||||
} else {
|
||||
get1.status(500)
|
||||
.result(objectmapper.writeValueAsString(resultMessage("Failed to export log to XLSX")))
|
||||
}
|
||||
} else get1.status(400)
|
||||
.result(objectmapper.writeValueAsString(resultMessage("Invalid logdate")))
|
||||
}
|
||||
path("Log") {
|
||||
get("/{datelog}") { ctx ->
|
||||
val datelog = ctx.pathParam("datelog")
|
||||
if (ValidDate(datelog)) {
|
||||
println("Request log for date: $datelog")
|
||||
if (ValiDateForLogHtml(datelog)) {
|
||||
db.GetLogForHtml(datelog) { loghtml ->
|
||||
val resultstring = objectmapper.writeValueAsString(loghtml)
|
||||
ctx.result(resultstring)
|
||||
|
||||
Reference in New Issue
Block a user