zet-lib 3.1.6 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/Model.js +10 -24
- package/lib/generatorModel.js +10 -0
- package/lib/zAppRouter.js +86 -0
- package/lib/zRoute.js +239 -90
- package/package.json +1 -1
package/lib/Model.js
CHANGED
|
@@ -1042,9 +1042,6 @@ Model.number = {
|
|
|
1042
1042
|
"defaultValue",
|
|
1043
1043
|
"inputGroupLeft",
|
|
1044
1044
|
"inputGroupRight",
|
|
1045
|
-
"digitDecimal",
|
|
1046
|
-
"decimalPlaces",
|
|
1047
|
-
"thousandSeparator",
|
|
1048
1045
|
"information",
|
|
1049
1046
|
],
|
|
1050
1047
|
attributes: ["min", "max"],
|
|
@@ -1058,9 +1055,6 @@ Model.number = {
|
|
|
1058
1055
|
defaultValue: "Default Value",
|
|
1059
1056
|
inputGroupLeft: "Input Group Left",
|
|
1060
1057
|
inputGroupRight: "Input Group Right",
|
|
1061
|
-
digitDecimal:"Digit Decimal",
|
|
1062
|
-
decimalPlaces:"Decimal Places",
|
|
1063
|
-
thousandSeparator:"Use 1000 Separator",
|
|
1064
1058
|
information: "Additional Information",
|
|
1065
1059
|
},
|
|
1066
1060
|
defaultValues: {
|
|
@@ -1073,9 +1067,6 @@ Model.number = {
|
|
|
1073
1067
|
defaultValue: null,
|
|
1074
1068
|
inputGroupLeft: "",
|
|
1075
1069
|
inputGroupRight: "",
|
|
1076
|
-
digitDecimal: 0,
|
|
1077
|
-
decimalPlaces:",",
|
|
1078
|
-
thousandSeparator:".",
|
|
1079
1070
|
information: "",
|
|
1080
1071
|
},
|
|
1081
1072
|
typies: {
|
|
@@ -1115,18 +1106,6 @@ Model.number = {
|
|
|
1115
1106
|
tag: "input",
|
|
1116
1107
|
type: "text",
|
|
1117
1108
|
},
|
|
1118
|
-
digitDecimal: {
|
|
1119
|
-
tag: "input",
|
|
1120
|
-
type: "number",
|
|
1121
|
-
},
|
|
1122
|
-
decimalPlaces: {
|
|
1123
|
-
tag: "input",
|
|
1124
|
-
type: "text",
|
|
1125
|
-
},
|
|
1126
|
-
thousandSeparator: {
|
|
1127
|
-
tag: "input",
|
|
1128
|
-
type: "text",
|
|
1129
|
-
},
|
|
1130
1109
|
information: {
|
|
1131
1110
|
tag: "textarea",
|
|
1132
1111
|
type: "",
|
|
@@ -2418,7 +2397,8 @@ Model.relation = {
|
|
|
2418
2397
|
"hidden",
|
|
2419
2398
|
"isSearch",
|
|
2420
2399
|
"order_by",
|
|
2421
|
-
"import_field"
|
|
2400
|
+
"import_field",
|
|
2401
|
+
"relation_info"
|
|
2422
2402
|
],
|
|
2423
2403
|
labels: {
|
|
2424
2404
|
required: "Required",
|
|
@@ -2435,7 +2415,8 @@ Model.relation = {
|
|
|
2435
2415
|
hidden: "Hidden",
|
|
2436
2416
|
isSearch:"Auto complete Search",
|
|
2437
2417
|
order_by : "Order By",
|
|
2438
|
-
import_field :"Default Import Field (id)"
|
|
2418
|
+
import_field :"Default Import Field (id)",
|
|
2419
|
+
relation_info : "Relation Data"
|
|
2439
2420
|
},
|
|
2440
2421
|
defaultValues: {
|
|
2441
2422
|
required: false,
|
|
@@ -2452,7 +2433,8 @@ Model.relation = {
|
|
|
2452
2433
|
hidden: false,
|
|
2453
2434
|
isSearch:false,
|
|
2454
2435
|
order_by : "",
|
|
2455
|
-
import_field :"id"
|
|
2436
|
+
import_field :"id",
|
|
2437
|
+
relation_info : "",
|
|
2456
2438
|
},
|
|
2457
2439
|
typies: {
|
|
2458
2440
|
required: {
|
|
@@ -2515,6 +2497,10 @@ Model.relation = {
|
|
|
2515
2497
|
tag: "input",
|
|
2516
2498
|
type: "text",
|
|
2517
2499
|
},
|
|
2500
|
+
relation_info : {
|
|
2501
|
+
tag: "textarea",
|
|
2502
|
+
rows: "3",
|
|
2503
|
+
},
|
|
2518
2504
|
},
|
|
2519
2505
|
comment: (obj) => {
|
|
2520
2506
|
return `select`;
|
package/lib/generatorModel.js
CHANGED
|
@@ -392,6 +392,16 @@ me.prepare = (MYMODEL) => {
|
|
|
392
392
|
widgets[key].please_select = property.values.please_select;
|
|
393
393
|
widgets[key].order_by = property.values.order_by;
|
|
394
394
|
widgets[key].import_field = property.values.import_field || "id";
|
|
395
|
+
widgets[key].relation_info = property.values.relation_info ? true : false;
|
|
396
|
+
if(widgets[key].relation_info) {
|
|
397
|
+
//create file info to runtime
|
|
398
|
+
let dirInfo = `${dirRoot}/public/runtime/info/${MYMODEL.table}`
|
|
399
|
+
//Util.writeFile(`${dirRoot}/runtime/info/${MYMODEL.tab}`)
|
|
400
|
+
if(!fs.existsSync(dirInfo)) {
|
|
401
|
+
fs.mkdirSync(dirInfo, { recursive: true });
|
|
402
|
+
}
|
|
403
|
+
fs.writeFileSync(`${dirInfo}/${key}.txt`, property.values.relation_info);
|
|
404
|
+
}
|
|
395
405
|
break;
|
|
396
406
|
case "dragdrop":
|
|
397
407
|
widgets[key].table = property.values.table;
|
package/lib/zAppRouter.js
CHANGED
|
@@ -2269,4 +2269,90 @@ router.post("/zcompress-dropbox", async (req, res) => {
|
|
|
2269
2269
|
res.json(Util.jsonSuccess("Compress all images completed..."));
|
|
2270
2270
|
});
|
|
2271
2271
|
|
|
2272
|
+
router.post('/zcall-information_info', async(req,res) => {
|
|
2273
|
+
let data = ''
|
|
2274
|
+
try {
|
|
2275
|
+
const {table, elementId, myvalue} = req.body;
|
|
2276
|
+
let content = Util.readFile(`${dirRoot}/public/runtime/info/${table}/${elementId}.txt`)
|
|
2277
|
+
data = content;
|
|
2278
|
+
|
|
2279
|
+
// Fungsi untuk mengekstrak semua field dari template
|
|
2280
|
+
const extractFields = (template) => {
|
|
2281
|
+
const regex = /\{\{([^}]+)\}\}/g;
|
|
2282
|
+
const fields = [];
|
|
2283
|
+
let match;
|
|
2284
|
+
while ((match = regex.exec(template)) !== null) {
|
|
2285
|
+
fields.push(match[1].trim());
|
|
2286
|
+
}
|
|
2287
|
+
return [...new Set(fields)]; // Remove duplicates
|
|
2288
|
+
};
|
|
2289
|
+
|
|
2290
|
+
if(content){
|
|
2291
|
+
let others = {}
|
|
2292
|
+
const MYMODELS = myCache.get("MYMODELS");
|
|
2293
|
+
let mymodel = MYMODELS[table];
|
|
2294
|
+
let mytable = mymodel.widgets[elementId].table;
|
|
2295
|
+
//console.log(mymodel);
|
|
2296
|
+
const result = await connection.result({
|
|
2297
|
+
table: mytable,
|
|
2298
|
+
where: {
|
|
2299
|
+
id: myvalue,
|
|
2300
|
+
},
|
|
2301
|
+
});
|
|
2302
|
+
//others = Object.assign({}, result);
|
|
2303
|
+
let fields = extractFields(content);
|
|
2304
|
+
fields.map((item) => {
|
|
2305
|
+
if(item.includes(".")){
|
|
2306
|
+
let name = item.split(".")[0];
|
|
2307
|
+
others[name] = {};
|
|
2308
|
+
}
|
|
2309
|
+
})
|
|
2310
|
+
|
|
2311
|
+
for(let key in others){
|
|
2312
|
+
let modelkey = MYMODELS[mytable].widgets[key].table;
|
|
2313
|
+
const resultkey = await connection.result({
|
|
2314
|
+
table: modelkey,
|
|
2315
|
+
where: {
|
|
2316
|
+
id: result[key],
|
|
2317
|
+
},
|
|
2318
|
+
});
|
|
2319
|
+
others[key] = resultkey;
|
|
2320
|
+
///disini saya ingin replace content dengan format {{}}
|
|
2321
|
+
//data = data.replace(`{{${key}}}`, resultkey[key]);
|
|
2322
|
+
|
|
2323
|
+
}
|
|
2324
|
+
let dataReplace = result;
|
|
2325
|
+
for(let key in others){
|
|
2326
|
+
dataReplace[key] = others[key];
|
|
2327
|
+
}
|
|
2328
|
+
console.log(dataReplace);
|
|
2329
|
+
|
|
2330
|
+
//saya ingin replace data dengan dataReplace
|
|
2331
|
+
// Fungsi untuk mendapatkan nilai dari path nested object
|
|
2332
|
+
const getNestedValue = (obj, path) => {
|
|
2333
|
+
const keys = path.split('.');
|
|
2334
|
+
let value = obj;
|
|
2335
|
+
for (const key of keys) {
|
|
2336
|
+
if (value && typeof value === 'object' && key in value) {
|
|
2337
|
+
value = value[key];
|
|
2338
|
+
} else {
|
|
2339
|
+
return ''; // Return empty string if path not found
|
|
2340
|
+
}
|
|
2341
|
+
}
|
|
2342
|
+
return value !== null && value !== undefined ? String(value) : '';
|
|
2343
|
+
};
|
|
2344
|
+
|
|
2345
|
+
// Replace semua placeholder {{field}} dengan nilai dari dataReplace
|
|
2346
|
+
data = content.replace(/\{\{([^}]+)\}\}/g, (match, fieldPath) => {
|
|
2347
|
+
const trimmedPath = fieldPath.trim();
|
|
2348
|
+
return getNestedValue(dataReplace, trimmedPath);
|
|
2349
|
+
});
|
|
2350
|
+
|
|
2351
|
+
}
|
|
2352
|
+
} catch (e) {
|
|
2353
|
+
console.log(e)
|
|
2354
|
+
}
|
|
2355
|
+
res.json(data)
|
|
2356
|
+
})
|
|
2357
|
+
|
|
2272
2358
|
module.exports = router;
|
package/lib/zRoute.js
CHANGED
|
@@ -4175,6 +4175,8 @@ zRoute.generateJS = (req, res, MYMODEL, relations, zForms = "", data = {}) => {
|
|
|
4175
4175
|
let joinsFields = [];
|
|
4176
4176
|
let selectize = [];
|
|
4177
4177
|
let moneys = [];
|
|
4178
|
+
let hasRelationInfo = false;
|
|
4179
|
+
let relationInfos = [];
|
|
4178
4180
|
if (MYMODEL.joins) {
|
|
4179
4181
|
joinsFields = MYMODEL.joins.list;
|
|
4180
4182
|
}
|
|
@@ -4267,6 +4269,11 @@ zRoute.generateJS = (req, res, MYMODEL, relations, zForms = "", data = {}) => {
|
|
|
4267
4269
|
selectize.push(key);
|
|
4268
4270
|
hasSelectize = true;
|
|
4269
4271
|
}
|
|
4272
|
+
if (widgets[key].relation_info) {
|
|
4273
|
+
hasRelationInfo = true;
|
|
4274
|
+
relationInfos.push(key);
|
|
4275
|
+
}
|
|
4276
|
+
|
|
4270
4277
|
}
|
|
4271
4278
|
}
|
|
4272
4279
|
}
|
|
@@ -4276,6 +4283,27 @@ zRoute.generateJS = (req, res, MYMODEL, relations, zForms = "", data = {}) => {
|
|
|
4276
4283
|
headObj.datepicker = datePickerObj.head;
|
|
4277
4284
|
endObj.datepicker = datePickerObj.end;
|
|
4278
4285
|
}
|
|
4286
|
+
if(hasRelationInfo){
|
|
4287
|
+
scriptForm += `function callRelationInfo(table, elementId, myvalue) {
|
|
4288
|
+
ajaxPost('/zcall-information_info',{table: table, elementId: elementId, myvalue: myvalue}, function (data) {
|
|
4289
|
+
let elemclass = 'information_' + elementId;
|
|
4290
|
+
if($("."+elemclass).length > 0){
|
|
4291
|
+
$("."+elemclass).html(data);
|
|
4292
|
+
} else {
|
|
4293
|
+
$(".div"+elementId).append('<div class="' + elemclass + ' mt-2 boxy">' + data + '</div>');
|
|
4294
|
+
}
|
|
4295
|
+
})
|
|
4296
|
+
} \r\n`
|
|
4297
|
+
let infoScript = '';
|
|
4298
|
+
relationInfos.map((relationInfo) => {
|
|
4299
|
+
infoScript += `$("#${relationInfo}").on('change', function () {
|
|
4300
|
+
callRelationInfo('${MYMODEL.table}','${relationInfo}', $(this).val())
|
|
4301
|
+
})
|
|
4302
|
+
callRelationInfo('${MYMODEL.table}','${relationInfo}', $("#${relationInfo}").val()) \r\n`
|
|
4303
|
+
})
|
|
4304
|
+
|
|
4305
|
+
scriptForm += `$(function() {${infoScript}});`;
|
|
4306
|
+
}
|
|
4279
4307
|
if (hasNumber) {
|
|
4280
4308
|
let numberObj = moduleLib.number(req, res);
|
|
4281
4309
|
scriptForm += numberObj.script;
|
|
@@ -6178,84 +6206,211 @@ zRoute.history = async (
|
|
|
6178
6206
|
users,
|
|
6179
6207
|
results = []
|
|
6180
6208
|
) => {
|
|
6181
|
-
|
|
6182
|
-
|
|
6183
|
-
|
|
6184
|
-
|
|
6185
|
-
|
|
6186
|
-
|
|
6187
|
-
|
|
6188
|
-
|
|
6189
|
-
|
|
6190
|
-
|
|
6191
|
-
|
|
6192
|
-
|
|
6193
|
-
|
|
6194
|
-
|
|
6195
|
-
|
|
6196
|
-
|
|
6197
|
-
|
|
6198
|
-
|
|
6199
|
-
|
|
6200
|
-
|
|
6201
|
-
|
|
6202
|
-
|
|
6203
|
-
|
|
6204
|
-
|
|
6205
|
-
|
|
6206
|
-
|
|
6207
|
-
|
|
6208
|
-
|
|
6209
|
-
|
|
6210
|
-
|
|
6211
|
-
|
|
6212
|
-
|
|
6213
|
-
|
|
6214
|
-
|
|
6215
|
-
|
|
6216
|
-
|
|
6217
|
-
|
|
6218
|
-
|
|
6219
|
-
|
|
6220
|
-
|
|
6221
|
-
|
|
6222
|
-
|
|
6223
|
-
|
|
6209
|
+
try {
|
|
6210
|
+
//html
|
|
6211
|
+
let html = "";
|
|
6212
|
+
|
|
6213
|
+
// Validasi input parameter
|
|
6214
|
+
if (!MYMODEL || !MYMODEL.widgets || !MYMODEL.labels) {
|
|
6215
|
+
return "Invalid model configuration";
|
|
6216
|
+
}
|
|
6217
|
+
|
|
6218
|
+
if (!users || typeof users !== 'object') {
|
|
6219
|
+
users = {};
|
|
6220
|
+
}
|
|
6221
|
+
|
|
6222
|
+
if (!Array.isArray(results)) {
|
|
6223
|
+
results = [];
|
|
6224
|
+
}
|
|
6225
|
+
|
|
6226
|
+
let unhistories = [
|
|
6227
|
+
"created_by",
|
|
6228
|
+
"updated_by",
|
|
6229
|
+
"created_at",
|
|
6230
|
+
"updated_at",
|
|
6231
|
+
"company_id",
|
|
6232
|
+
"id",
|
|
6233
|
+
];
|
|
6234
|
+
let arrHistories = [];
|
|
6235
|
+
let arrDataAttributes = [];
|
|
6236
|
+
let objectType = [
|
|
6237
|
+
"dropzone",
|
|
6238
|
+
"dropdown_multi",
|
|
6239
|
+
"dropdown_checkbox",
|
|
6240
|
+
"array",
|
|
6241
|
+
"json_array",
|
|
6242
|
+
"table",
|
|
6243
|
+
"json",
|
|
6244
|
+
];
|
|
6245
|
+
const widgets = MYMODEL.widgets;
|
|
6246
|
+
let fields = Object.keys(MYMODEL.labels || {});
|
|
6247
|
+
|
|
6248
|
+
if (results.length == 0) {
|
|
6249
|
+
html = "No History...";
|
|
6250
|
+
} else {
|
|
6251
|
+
for (const result of results) {
|
|
6252
|
+
try {
|
|
6253
|
+
if (!result || typeof result !== 'object') {
|
|
6254
|
+
continue;
|
|
6255
|
+
}
|
|
6256
|
+
|
|
6257
|
+
let obj = {};
|
|
6258
|
+
let data1 = result.data_1 || {};
|
|
6259
|
+
let data2 = result.data_2 || {};
|
|
6260
|
+
|
|
6261
|
+
if (!data1 || typeof data1 !== 'object') {
|
|
6262
|
+
data1 = {};
|
|
6263
|
+
}
|
|
6264
|
+
if (!data2 || typeof data2 !== 'object') {
|
|
6265
|
+
data2 = {};
|
|
6266
|
+
}
|
|
6267
|
+
|
|
6268
|
+
for (const key in data1) {
|
|
6269
|
+
try {
|
|
6270
|
+
if (!unhistories.includes(key)) {
|
|
6271
|
+
if (fields.includes(key)) {
|
|
6272
|
+
if (data1[key] || data2[key]) {
|
|
6273
|
+
// Validasi widget exists
|
|
6274
|
+
if (!MYMODEL.widgets[key] || !MYMODEL.widgets[key].name) {
|
|
6275
|
+
continue;
|
|
6276
|
+
}
|
|
6277
|
+
|
|
6278
|
+
let name = MYMODEL.widgets[key].name;
|
|
6279
|
+
if (objectType.includes(name)) {
|
|
6280
|
+
try {
|
|
6281
|
+
if (JSON.stringify(data1[key]) != JSON.stringify(data2[key])) {
|
|
6282
|
+
obj[key] = [data1[key], data2[key]];
|
|
6283
|
+
}
|
|
6284
|
+
} catch (jsonError) {
|
|
6285
|
+
// Jika JSON.stringify error, gunakan perbandingan biasa
|
|
6286
|
+
if (data1[key] != data2[key]) {
|
|
6287
|
+
obj[key] = [data1[key], data2[key]];
|
|
6288
|
+
}
|
|
6289
|
+
}
|
|
6290
|
+
} else {
|
|
6291
|
+
if (data1[key] != data2[key]) {
|
|
6292
|
+
obj[key] = [data1[key], data2[key]];
|
|
6293
|
+
}
|
|
6294
|
+
}
|
|
6295
|
+
}
|
|
6224
6296
|
}
|
|
6225
6297
|
}
|
|
6298
|
+
} catch (keyError) {
|
|
6299
|
+
// Skip key yang error, lanjut ke key berikutnya
|
|
6300
|
+
console.error(`Error processing key ${key}:`, keyError);
|
|
6301
|
+
continue;
|
|
6226
6302
|
}
|
|
6227
6303
|
}
|
|
6304
|
+
|
|
6305
|
+
if (Object.keys(obj).length > 0) {
|
|
6306
|
+
arrHistories.push(obj);
|
|
6307
|
+
arrDataAttributes.push({
|
|
6308
|
+
date1: result.data_1_date || null,
|
|
6309
|
+
date2: result.data_2_date || null,
|
|
6310
|
+
by1: (result.data_1 && result.data_1.updated_by) || null,
|
|
6311
|
+
by2: result.created_by || null,
|
|
6312
|
+
});
|
|
6313
|
+
}
|
|
6314
|
+
} catch (resultError) {
|
|
6315
|
+
// Skip result yang error, lanjut ke result berikutnya
|
|
6316
|
+
console.error('Error processing result:', resultError);
|
|
6317
|
+
continue;
|
|
6228
6318
|
}
|
|
6229
6319
|
}
|
|
6230
|
-
if (Object.keys(obj).length > 0) {
|
|
6231
|
-
arrHistories.push(obj);
|
|
6232
|
-
arrDataAttributes.push({
|
|
6233
|
-
date1: result.data_1_date,
|
|
6234
|
-
date2: result.data_2_date,
|
|
6235
|
-
by1: result.data_1.updated_by,
|
|
6236
|
-
by2: result.created_by,
|
|
6237
|
-
});
|
|
6238
|
-
}
|
|
6239
|
-
}
|
|
6240
6320
|
|
|
6241
|
-
|
|
6242
|
-
|
|
6243
|
-
|
|
6244
|
-
|
|
6245
|
-
|
|
6246
|
-
|
|
6247
|
-
|
|
6248
|
-
|
|
6249
|
-
|
|
6250
|
-
|
|
6251
|
-
|
|
6252
|
-
|
|
6253
|
-
|
|
6254
|
-
|
|
6255
|
-
|
|
6256
|
-
|
|
6321
|
+
let index = 0;
|
|
6322
|
+
for (const item of arrHistories) {
|
|
6323
|
+
try {
|
|
6324
|
+
if (!item || typeof item !== 'object') {
|
|
6325
|
+
index++;
|
|
6326
|
+
continue;
|
|
6327
|
+
}
|
|
6328
|
+
|
|
6329
|
+
let obj1 = {};
|
|
6330
|
+
let obj2 = {};
|
|
6331
|
+
for (let key in item) {
|
|
6332
|
+
if (Array.isArray(item[key]) && item[key].length >= 2) {
|
|
6333
|
+
obj1[key] = item[key][0];
|
|
6334
|
+
obj2[key] = item[key][1];
|
|
6335
|
+
}
|
|
6336
|
+
}
|
|
6337
|
+
|
|
6338
|
+
let viewFormsSync1, viewFormsSync2;
|
|
6339
|
+
try {
|
|
6340
|
+
viewFormsSync1 = await zRoute.viewFormsSync(req, res, MYMODEL, obj1);
|
|
6341
|
+
viewFormsSync2 = await zRoute.viewFormsSync(req, res, MYMODEL, obj2);
|
|
6342
|
+
} catch (viewFormsError) {
|
|
6343
|
+
console.error('Error in viewFormsSync:', viewFormsError);
|
|
6344
|
+
index++;
|
|
6345
|
+
continue;
|
|
6346
|
+
}
|
|
6347
|
+
|
|
6348
|
+
if (!viewFormsSync1 || !viewFormsSync1.build) {
|
|
6349
|
+
viewFormsSync1 = { build: {} };
|
|
6350
|
+
}
|
|
6351
|
+
if (!viewFormsSync2 || !viewFormsSync2.build) {
|
|
6352
|
+
viewFormsSync2 = { build: {} };
|
|
6353
|
+
}
|
|
6354
|
+
|
|
6355
|
+
let html1 = "";
|
|
6356
|
+
let html2 = "";
|
|
6357
|
+
for (let key in item) {
|
|
6358
|
+
html1 += (viewFormsSync1.build[key] || '');
|
|
6359
|
+
html2 += (viewFormsSync2.build[key] || '');
|
|
6360
|
+
}
|
|
6361
|
+
|
|
6362
|
+
// Validasi arrDataAttributes[index]
|
|
6363
|
+
const dataAttr = arrDataAttributes[index] || {};
|
|
6364
|
+
const date1 = dataAttr.date1 || null;
|
|
6365
|
+
const date2 = dataAttr.date2 || null;
|
|
6366
|
+
const by1 = dataAttr.by1 || null;
|
|
6367
|
+
const by2 = dataAttr.by2 || null;
|
|
6257
6368
|
|
|
6258
|
-
|
|
6369
|
+
// Validasi users sebelum mengakses fullname
|
|
6370
|
+
let user1Fullname = '';
|
|
6371
|
+
let user2Fullname = '';
|
|
6372
|
+
|
|
6373
|
+
try {
|
|
6374
|
+
if (by1 && users[by1] && users[by1].fullname) {
|
|
6375
|
+
user1Fullname = users[by1].fullname;
|
|
6376
|
+
} else {
|
|
6377
|
+
user1Fullname = by1 || 'Unknown';
|
|
6378
|
+
}
|
|
6379
|
+
} catch (user1Error) {
|
|
6380
|
+
user1Fullname = by1 || 'Unknown';
|
|
6381
|
+
}
|
|
6382
|
+
|
|
6383
|
+
try {
|
|
6384
|
+
if (by2 && users[by2] && users[by2].fullname) {
|
|
6385
|
+
user2Fullname = users[by2].fullname;
|
|
6386
|
+
} else {
|
|
6387
|
+
user2Fullname = by2 || 'Unknown';
|
|
6388
|
+
}
|
|
6389
|
+
} catch (user2Error) {
|
|
6390
|
+
user2Fullname = by2 || 'Unknown';
|
|
6391
|
+
}
|
|
6392
|
+
|
|
6393
|
+
// Format date dengan error handling
|
|
6394
|
+
let formattedDate1 = '';
|
|
6395
|
+
let formattedDate2 = '';
|
|
6396
|
+
|
|
6397
|
+
try {
|
|
6398
|
+
if (date1 && Util && Util.dateFormat) {
|
|
6399
|
+
formattedDate1 = Util.dateFormat(date1, "DD MMM YYYY HH:mm") || "";
|
|
6400
|
+
}
|
|
6401
|
+
} catch (date1Error) {
|
|
6402
|
+
formattedDate1 = '';
|
|
6403
|
+
}
|
|
6404
|
+
|
|
6405
|
+
try {
|
|
6406
|
+
if (date2 && Util && Util.dateFormat) {
|
|
6407
|
+
formattedDate2 = Util.dateFormat(date2, "DD MMM YYYY HH:mm") || "";
|
|
6408
|
+
}
|
|
6409
|
+
} catch (date2Error) {
|
|
6410
|
+
formattedDate2 = '';
|
|
6411
|
+
}
|
|
6412
|
+
|
|
6413
|
+
html += `<div class="row">
|
|
6259
6414
|
<!-- timeline item 1 left dot -->
|
|
6260
6415
|
<div class="col-auto text-center flex-column d-none d-sm-flex">
|
|
6261
6416
|
<div class="row h-50">
|
|
@@ -6276,15 +6431,7 @@ zRoute.history = async (
|
|
|
6276
6431
|
<div class="col-md-6">
|
|
6277
6432
|
<div class="card">
|
|
6278
6433
|
<div class="card-body">
|
|
6279
|
-
<div class="float-end text-muted text-end">${
|
|
6280
|
-
Util.dateFormat(
|
|
6281
|
-
arrDataAttributes[index]
|
|
6282
|
-
.date1,
|
|
6283
|
-
"DD MMM YYYY HH:mm"
|
|
6284
|
-
) || ""
|
|
6285
|
-
}<br><small>${
|
|
6286
|
-
users[arrDataAttributes[index].by1].fullname
|
|
6287
|
-
}</small></div>
|
|
6434
|
+
<div class="float-end text-muted text-end">${formattedDate1}<br><small>${user1Fullname}</small></div>
|
|
6288
6435
|
<h4 class="card-title text-muted">Semula</h4>
|
|
6289
6436
|
<div class="card-text">${html1}</div>
|
|
6290
6437
|
</div>
|
|
@@ -6293,15 +6440,7 @@ zRoute.history = async (
|
|
|
6293
6440
|
<div class="col-md-6">
|
|
6294
6441
|
<div class="card">
|
|
6295
6442
|
<div class="card-body">
|
|
6296
|
-
<div class="float-end text-muted text-end">${
|
|
6297
|
-
Util.dateFormat(
|
|
6298
|
-
arrDataAttributes[index]
|
|
6299
|
-
.date2,
|
|
6300
|
-
"DD MMM YYYY HH:mm"
|
|
6301
|
-
) || ""
|
|
6302
|
-
} <br><small>${
|
|
6303
|
-
users[arrDataAttributes[index].by2].fullname
|
|
6304
|
-
}</small></div>
|
|
6443
|
+
<div class="float-end text-muted text-end">${formattedDate2} <br><small>${user2Fullname}</small></div>
|
|
6305
6444
|
<h4 class="card-title text-success">Menjadi </h4>
|
|
6306
6445
|
<div class="card-text">${html2}</div>
|
|
6307
6446
|
</div>
|
|
@@ -6311,10 +6450,20 @@ zRoute.history = async (
|
|
|
6311
6450
|
</div>
|
|
6312
6451
|
</div>`;
|
|
6313
6452
|
|
|
6314
|
-
|
|
6453
|
+
index++;
|
|
6454
|
+
} catch (itemError) {
|
|
6455
|
+
// Skip item yang error, lanjut ke item berikutnya
|
|
6456
|
+
console.error(`Error processing history item at index ${index}:`, itemError);
|
|
6457
|
+
index++;
|
|
6458
|
+
continue;
|
|
6459
|
+
}
|
|
6460
|
+
}
|
|
6315
6461
|
}
|
|
6462
|
+
return html;
|
|
6463
|
+
} catch (error) {
|
|
6464
|
+
console.error('Error in zRoute.history:', error);
|
|
6465
|
+
return "Error loading history. Please try again later.";
|
|
6316
6466
|
}
|
|
6317
|
-
return html;
|
|
6318
6467
|
};
|
|
6319
6468
|
|
|
6320
6469
|
zRoute.tableBody = (
|