4949 class =" fa fa-print" ></i >
5050 Cetak</button >
5151 </div >
52+ <div class =" col-md-2" >
53+ <button type =" button" id =" export-excel" class =" btn btn-info btn-block btn-sm" >
54+ <i class =" fa fa-file-excel" ></i >
55+ Excel
56+ </button >
57+ </div >
5258 <div class =" col-md-2" >
5359 <button id =" btn-grafik" class =" btn btn-sm btn-success btn-block btn-sm" data-toggle =" collapse"
5460 href =" #grafik-statistik" role =" button" aria-expanded =" false"
@@ -149,7 +155,7 @@ class="fa fa-print"></i>
149155 <thead >
150156 <tr >
151157 <th >No</th >
152- <th id =" judul_kolom_nama" width =" 50%" ></th >
158+ <th id =" judul_kolom_nama" width =" 50%" >Jenis Kelompok </th >
153159 <th colspan =" 2" class =" dt-head-center" >Jumlah</th >
154160 <th colspan =" 2" class =" dt-head-center" >Laki - laki</th >
155161 <th colspan =" 2" class =" dt-head-center" >Perempuan</th >
@@ -165,6 +171,7 @@ class="fa fa-print"></i>
165171@endsection
166172
167173@section (' js' )
174+ <script nonce =" {{ csp_nonce () } }" src =" {{ asset (' assets/js/excellentexport.js' ) } }" ></script >
168175 @include (' statistik.chart' )
169176 <script nonce =" {{ csp_nonce () } }" >
170177 let data_grafik = [];
@@ -241,6 +248,190 @@ class="fa fa-print"></i>
241248 window .open (url, ' _blank' );
242249 });
243250
251+ // Helper function to create Excel export caption
252+ function createExportCaption (categoryName , options = {}) {
253+ const {
254+ includeDate = true ,
255+ includeLocation = true ,
256+ includePeriod = true ,
257+ customTitle = null ,
258+ } = options;
259+
260+ var caption = {
261+ title: customTitle || ` Data Statistik ${ categoryName} ` ,
262+ period: ' ' ,
263+ date: ' ' ,
264+ location: ' '
265+ };
266+
267+ // Add period information
268+ if (includePeriod) {
269+ var tahun = $ (" #tahun" ).val ();
270+ var bulan = $ (" #bulan" ).val ();
271+
272+ if (tahun || bulan) {
273+ var periodParts = [];
274+ if (bulan) {
275+ const bulanNames = [' ' , ' Januari' , ' Februari' , ' Maret' , ' April' , ' Mei' , ' Juni' ,
276+ ' Juli' , ' Agustus' , ' September' , ' Oktober' , ' November' , ' Desember'
277+ ];
278+ periodParts .push (` Bulan: ${ bulanNames[parseInt (bulan)]} ` );
279+ }
280+ if (tahun) {
281+ periodParts .push (` Tahun: ${ tahun} ` );
282+ }
283+ caption .period = periodParts .join (' | ' );
284+ }
285+ }
286+
287+ // Add export date
288+ if (includeDate) {
289+ var now = new Date ();
290+ caption .date =
291+ ` Diekspor pada: ${ now .toLocaleDateString (' id-ID' )} ${ now .toLocaleTimeString (' id-ID' )} ` ;
292+ }
293+
294+ // Add location info
295+ if (includeLocation) {
296+ caption .location =
297+ ` Kabupaten: {{ session (' kabupaten.nama_kabupaten' ) ?? ' N/A' } } | Kecamatan: {{ session (' kecamatan.nama_kecamatan' ) ?? ' N/A' } }` ;
298+ }
299+
300+ return caption;
301+ }
302+
303+ // Function to generate dynamic Excel export
304+ function exportToExcel () {
305+ console .log (' Starting Excel export...' );
306+
307+ // Check if table has data
308+ var tableRows = $ (' #tabel-data tbody tr' ).length ;
309+ console .log (' Table rows count:' , tableRows);
310+
311+ if (tableRows === 0 ) {
312+ alert (' Tidak ada data untuk diekspor. Silakan pilih kategori terlebih dahulu.' );
313+ return false ;
314+ }
315+
316+ // Get current active category
317+ var activeCategory = $ (' #daftar-statistik .active' );
318+ var categoryName = activeCategory .data (' nama' ) || ' Statistik' ;
319+ var tahun = $ (" #tahun" ).val ();
320+ var bulan = $ (" #bulan" ).val ();
321+
322+ console .log (' Category:' , categoryName, ' Year:' , tahun, ' Month:' , bulan);
323+
324+ // Generate dynamic filename
325+ var filename = ` Statistik_${ categoryName} _${ nama_desa} ` ;
326+ if (tahun) {
327+ filename += ` _${ tahun} ` ;
328+ }
329+ if (bulan) {
330+ const bulanNames = [' ' , ' Januari' , ' Februari' , ' Maret' , ' April' , ' Mei' , ' Juni' ,
331+ ' Juli' , ' Agustus' , ' September' , ' Oktober' , ' November' , ' Desember'
332+ ];
333+ filename += ` _${ bulanNames[parseInt (bulan)]} ` ;
334+ }
335+
336+ // Clean filename - remove special characters
337+ filename = filename .replace (/ [^ a-zA-Z0-9 _-] / g , ' _' );
338+
339+ // Generate sheet name (max 31 chars for Excel)
340+ var sheetName = categoryName .replace (/ [^ a-zA-Z0-9 ] / g , ' _' ).substring (0 , 31 ) || ' Statistik' ;
341+
342+ // Create export caption using helper function
343+ // Anda bisa mengkustomisasi caption dengan mengubah opsi di bawah ini:
344+ var caption = createExportCaption (categoryName, {
345+ includeDate: true , // Tampilkan tanggal export
346+ includeLocation: false , // Tampilkan info kabupaten/kecamatan
347+ includePeriod: true , // Tampilkan info tahun/bulan
348+ customTitle: ` Laporan Statistik {{ $judul } } Kategori ${ categoryName} ` , // Custom judul utama
349+ });
350+
351+ // Create a clone of the table for export
352+ var $originalTable = $ (' #tabel-data' );
353+ var $exportTable = $originalTable .clone ();
354+ $exportTable .attr (' id' , ' export-table' );
355+
356+ // Add title rows before the header
357+ var titleRows = ' ' ;
358+ titleRows +=
359+ ` <tr><td colspan="8" style="text-align: center; font-weight: bold; font-size: 18px; background-color: #2c3e50; color: white; padding: 10px;">${ caption .title } </td></tr>` ;
360+
361+ if (caption .period ) {
362+ titleRows +=
363+ ` <tr><td colspan="8" style="text-align: center; font-size: 12px; background-color: #ecf0f1; padding: 5px;">${ caption .period } </td></tr>` ;
364+ }
365+
366+ if (caption .date ) {
367+ titleRows +=
368+ ` <tr><td colspan="8" style="text-align: center; font-size: 10px; background-color: #bdc3c7; padding: 3px;">${ caption .date } </td></tr>` ;
369+ }
370+
371+ // Add empty row for spacing
372+ titleRows += ' <tr><td colspan="8" style="height: 15px; background-color: white;"></td></tr>' ;
373+
374+ // Insert title rows into the table
375+ $exportTable .find (' thead' ).prepend (titleRows);
376+
377+ // Add footer information
378+ var footerRows = ' ' ;
379+ footerRows += ' <tr><td colspan="8" style="height: 15px; background-color: white;"></td></tr>' ;
380+ footerRows +=
381+ ` <tr><td colspan="8" style="text-align: left; font-size: 10px; background-color: #ecf0f1; padding: 5px;">Catatan: Data statistik ini dihasilkan dari sistem informasi desa</td></tr>` ;
382+
383+ if (caption .location ) {
384+ footerRows +=
385+ ` <tr><td colspan="8" style="text-align: left; font-size: 10px; background-color: #ecf0f1; padding: 5px;">${ caption .location } </td></tr>` ;
386+ }
387+
388+ // Add footer to table
389+ $exportTable .find (' tbody' ).append (footerRows);
390+
391+ // Temporarily add the export table to DOM (hidden)
392+ $exportTable .css (' display' , ' none' );
393+ $ (' body' ).append ($exportTable);
394+
395+ // Create temporary anchor with proper attributes
396+ var tempAnchor = document .createElement (' a' );
397+ tempAnchor .download = filename + ' .xls' ;
398+ tempAnchor .href = ' #' ;
399+ tempAnchor .setAttribute (' download' , filename + ' .xls' );
400+
401+ // Add to DOM temporarily
402+ document .body .appendChild (tempAnchor);
403+
404+ try {
405+ // Call ExcellentExport directly using the export table
406+ console .log (' Calling ExcellentExport.excel...' );
407+ var result = ExcellentExport .excel (tempAnchor, ' export-table' , sheetName);
408+ console .log (' Export result:' , result);
409+
410+ if (result) {
411+ tempAnchor .click (); // Trigger download
412+ // Optional: Show success message
413+ console .log (' File Excel berhasil diunduh: ' + filename + ' .xls' );
414+ } else {
415+ console .error (' Excel export failed - no result returned' );
416+ alert (' Gagal mengunduh file Excel. Silakan coba lagi.' );
417+ }
418+ } catch (error) {
419+ console .error (' Excel export error:' , error);
420+ alert (' Terjadi kesalahan saat mengunduh Excel: ' + error .message );
421+ } finally {
422+ // Clean up
423+ document .body .removeChild (tempAnchor);
424+ $ (' #export-table' ).remove (); // Remove the temporary table
425+ }
426+
427+ return result;
428+ }
429+
430+ $ (' #export-excel' ).on (' click' , function () {
431+ console .log (' Export button clicked' );
432+ exportToExcel ();
433+ });
434+
244435 $ (' #btn-grafik' ).on (' click' , function () {
245436 $ (" #pie-statistik" ).collapse (' hide' );
246437 });
@@ -322,24 +513,26 @@ className: 'dt-body-right',
322513 columns: [{
323514 data: null ,
324515 }, {
325- data : function (data ) {
516+ data : function (data ) {
326517
327518 const id = data .id ? .toString () ?? ' ' ;
328519
329- if (data .attributes .nama !== ' JUMLAH' && data .attributes .nama !== ' BELUM MENGISI' && data .attributes .nama !== ' TOTAL' ){
520+ if (data .attributes .nama !== ' JUMLAH' && data .attributes .nama !==
521+ ' BELUM MENGISI' && data .attributes .nama !== ' TOTAL' ) {
330522
331523 let kriteria = new URLSearchParams (JSON .parse (data .attributes
332524 .kriteria ));
333-
525+
334526 let judul = $ (' .pilih-kategori > a.active' ).text () + ' : ' + data
335527 .attributes .nama ;
336528 let urlDetail = new URL (urlDetailLink);
337529 urlDetail .searchParams .set (' filter[kriteria]' , kriteria .toString ());
338530 urlDetail .searchParams .set (' judul' , judul);
339531 urlDetail .searchParams .set (' nama' , data .attributes .nama );
340- urlDetail .searchParams .set (' tipe' , $ (' .pilih-kategori > a.active' ).text ().trim ());
532+ urlDetail .searchParams .set (' tipe' , $ (' .pilih-kategori > a.active' )
533+ .text ().trim ());
341534 urlDetail .searchParams .set (' chart-view' , true );
342-
535+
343536 return ` <a target="_blank" href=${ urlDetail .href } >${ data .attributes .nama } </a>`
344537 }
345538
0 commit comments