alterzick commited on
Commit
543dd2f
·
verified ·
1 Parent(s): d091acb

Add 2 files

Browse files
Files changed (2) hide show
  1. index.html +175 -45
  2. prompts.txt +2 -1
index.html CHANGED
@@ -5,8 +5,8 @@
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
6
  <title>Rig Operation Procedure Builder - LEGO Style</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
8
- <script src="https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js"></script>
9
- <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
10
  <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
11
  <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap" rel="stylesheet">
12
  <style>
@@ -60,6 +60,9 @@
60
  <button id="downloadWordBtn" class="bg-purple-600 hover:bg-purple-700 text-white px-5 py-2 rounded-lg text-sm font-medium flex items-center gap-1 transition">
61
  <i class="fas fa-file-word"></i> Download Word
62
  </button>
 
 
 
63
  <button id="approvalBtn" class="bg-orange-500 hover:bg-orange-600 text-white px-5 py-2 rounded-lg text-sm font-medium flex items-center gap-1 transition">
64
  <i class="fas fa-check-circle"></i> Submit for Approval
65
  </button>
@@ -332,6 +335,7 @@
332
  const saveBtn = document.getElementById('saveBtn');
333
  const printBtn = document.getElementById('printBtn');
334
  const downloadWordBtn = document.getElementById('downloadWordBtn');
 
335
  const approvalBtn = document.getElementById('approvalBtn');
336
 
337
  // Initialize
@@ -402,9 +406,8 @@
402
  // Click on builder to add
403
  builder.addEventListener('click', (e) => {
404
  if (e.target === builder || e.target === placeholder) {
405
- // Show quick add menu
406
  if (blocks.length === 0) {
407
- addBlock('step'); // Default
408
  }
409
  }
410
  });
@@ -417,11 +420,9 @@
417
  template.id = id;
418
  template.style.display = 'block';
419
 
420
- // Set step number
421
  const stepNumber = template.querySelector('.step-number');
422
  stepNumber.textContent = procedureCounter++;
423
 
424
- // Handle dynamic content
425
  if (type === 'material') {
426
  setupMaterialBlock(template);
427
  } else if (type === 'personnel') {
@@ -432,7 +433,6 @@
432
  setupUploadArea(template);
433
  }
434
 
435
- // Add event listeners to controls
436
  template.querySelector('.remove-block').addEventListener('click', () => {
437
  if (confirm('Are you sure you want to remove this block?')) {
438
  template.remove();
@@ -441,13 +441,9 @@
441
  });
442
 
443
  template.querySelector('.edit-block').addEventListener('click', () => {
444
- alert('Edit mode activated for this block. You can now modify the content.');
445
- // Just focus the first input/textarea
446
- const firstInput = template.querySelector('input, textarea');
447
- if (firstInput) firstInput.focus();
448
  });
449
 
450
- // Make block draggable
451
  template.setAttribute('draggable', true);
452
  template.addEventListener('dragstart', (e) => {
453
  e.dataTransfer.setData('text/plain', 'move');
@@ -459,11 +455,9 @@
459
  template.classList.remove('dragging');
460
  });
461
 
462
- // Append to builder
463
  builder.appendChild(template);
464
  placeholder.style.display = 'none';
465
 
466
- // Save state
467
  blocks.push({ id, type, element: template });
468
  }
469
 
@@ -492,7 +486,7 @@
492
  }
493
 
494
  addButton.addEventListener('click', addMaterialItem);
495
- addMaterialItem(); // Add first item by default
496
  }
497
 
498
  function setupPersonnelBlock(block) {
@@ -520,7 +514,7 @@
520
  }
521
 
522
  addButton.addEventListener('click', addPersonnelItem);
523
- addPersonnelItem(); // Add first item by default
524
  }
525
 
526
  function setupChecklistBlock(block) {
@@ -542,7 +536,7 @@
542
  }
543
 
544
  addButton.addEventListener('click', addChecklistItem);
545
- addChecklistItem(); // Add first item by default
546
  }
547
 
548
  function setupUploadArea(block) {
@@ -566,7 +560,6 @@
566
  }
567
  });
568
 
569
- // Drag and drop for file
570
  area.addEventListener('drop', (e) => {
571
  e.preventDefault();
572
  const file = e.dataTransfer.files[0];
@@ -584,7 +577,6 @@
584
  });
585
  }
586
 
587
- // Update step numbers sequentially
588
  function updateStepNumbers() {
589
  procedureCounter = 1;
590
  document.querySelectorAll('.procedure-block').forEach(block => {
@@ -595,9 +587,7 @@
595
  });
596
  }
597
 
598
- // Setup global events
599
  function setupEvents() {
600
- // Reorder blocks via drag and drop
601
  builder.addEventListener('dragover', (e) => {
602
  e.preventDefault();
603
  const afterElement = getDragAfterElement(builder, e.clientY);
@@ -609,7 +599,6 @@
609
  }
610
  });
611
 
612
- // Save procedure
613
  saveBtn.addEventListener('click', () => {
614
  const title = prompt('Enter procedure title:', 'New Procedure') || 'Untitled';
615
  const id = 'PRC-' + Date.now().toString().substr(-6).toUpperCase();
@@ -629,7 +618,6 @@
629
  })
630
  };
631
 
632
- // Save to "database" (localStorage)
633
  let procedures = JSON.parse(localStorage.getItem('rigProcedures') || '[]');
634
  procedures.push(procedure);
635
  localStorage.setItem('rigProcedures', JSON.stringify(procedures));
@@ -638,27 +626,178 @@
638
  loadProcedures();
639
  });
640
 
641
- // Print
642
  printBtn.addEventListener('click', () => {
643
  window.print();
644
  });
645
 
646
- // Download as Word (using HTML to DOCX approach via PDF for simplicity)
647
  downloadWordBtn.addEventListener('click', () => {
648
- const { jsPDF } = window.jspdf;
649
-
650
- html2canvas(document.getElementById('procedureBuilder')).then(canvas => {
651
- const imgData = canvas.toDataURL('image/png');
652
- const pdf = new jsPDF();
653
- const imgProps = pdf.getImageProperties(imgData);
654
- const pdfWidth = pdf.internal.pageSize.getWidth();
655
- const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width;
656
- pdf.addImage(imgData, 'PNG', 0, 0, pdfWidth, pdfHeight);
657
- pdf.save("rig-procedure.pdf");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
658
  });
659
  });
660
 
661
- // Submit for approval
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
662
  approvalBtn.addEventListener('click', () => {
663
  if (blocks.length === 0) {
664
  alert('Please add at least one block before submitting.');
@@ -666,7 +805,6 @@
666
  }
667
  if (confirm('Submit this procedure for approval? It will be reviewed by the safety team.')) {
668
  const procedures = JSON.parse(localStorage.getItem('rigProcedures') || '[]');
669
- // Update the last saved one
670
  if (procedures.length > 0) {
671
  procedures[procedures.length - 1].status = 'Pending';
672
  localStorage.setItem('rigProcedures', JSON.stringify(procedures));
@@ -690,7 +828,6 @@
690
  }, { offset: Number.NEGATIVE_INFINITY }).element;
691
  }
692
 
693
- // Load procedures from localStorage
694
  function loadProcedures() {
695
  const tableBody = document.getElementById('procedureTableBody');
696
  tableBody.innerHTML = '';
@@ -716,7 +853,6 @@
716
  tableBody.appendChild(tr);
717
  });
718
 
719
- // Add event listeners
720
  document.querySelectorAll('.edit-proc').forEach(btn => {
721
  btn.addEventListener('click', (e) => {
722
  const id = e.target.dataset.id;
@@ -737,19 +873,16 @@
737
  const procedure = procedures.find(p => p.id === id);
738
  if (!procedure) return;
739
 
740
- // Clear current builder
741
  builder.innerHTML = '';
742
  blocks = [];
743
  procedureCounter = 1;
744
 
745
- // Add blocks
746
  procedure.blocks.forEach(blockObj => {
747
  const div = document.createElement('div');
748
  div.innerHTML = blockObj.html;
749
  const block = div.firstElementChild;
750
  block.style.display = 'block';
751
 
752
- // Remove events and make readonly if needed
753
  if (readOnly) {
754
  block.querySelectorAll('input, textarea, button').forEach(el => {
755
  if (el.type !== 'checkbox') {
@@ -761,7 +894,6 @@
761
  });
762
  block.removeAttribute('draggable');
763
  } else {
764
- // Reattach events
765
  block.querySelector('.remove-block').addEventListener('click', () => {
766
  if (confirm('Remove this block?')) {
767
  block.remove();
@@ -781,11 +913,9 @@
781
  updateStepNumbers();
782
  }
783
 
784
- // Start app
785
  window.addEventListener('DOMContentLoaded', init);
786
  </script>
787
 
788
- <!-- Print Styling -->
789
  <style media="print">
790
  .toolbox, .toolbox-item, #placeholder, .edit-block, .remove-block {
791
  display: none !important;
 
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
6
  <title>Rig Operation Procedure Builder - LEGO Style</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js"></script>
9
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/docx/7.2.0/docx.js"></script>
10
  <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
11
  <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap" rel="stylesheet">
12
  <style>
 
60
  <button id="downloadWordBtn" class="bg-purple-600 hover:bg-purple-700 text-white px-5 py-2 rounded-lg text-sm font-medium flex items-center gap-1 transition">
61
  <i class="fas fa-file-word"></i> Download Word
62
  </button>
63
+ <button id="downloadRTFBtn" class="bg-teal-600 hover:bg-teal-700 text-white px-5 py-2 rounded-lg text-sm font-medium flex items-center gap-1 transition">
64
+ <i class="fas fa-file-alt"></i> Download RTF
65
+ </button>
66
  <button id="approvalBtn" class="bg-orange-500 hover:bg-orange-600 text-white px-5 py-2 rounded-lg text-sm font-medium flex items-center gap-1 transition">
67
  <i class="fas fa-check-circle"></i> Submit for Approval
68
  </button>
 
335
  const saveBtn = document.getElementById('saveBtn');
336
  const printBtn = document.getElementById('printBtn');
337
  const downloadWordBtn = document.getElementById('downloadWordBtn');
338
+ const downloadRTFBtn = document.getElementById('downloadRTFBtn');
339
  const approvalBtn = document.getElementById('approvalBtn');
340
 
341
  // Initialize
 
406
  // Click on builder to add
407
  builder.addEventListener('click', (e) => {
408
  if (e.target === builder || e.target === placeholder) {
 
409
  if (blocks.length === 0) {
410
+ addBlock('step');
411
  }
412
  }
413
  });
 
420
  template.id = id;
421
  template.style.display = 'block';
422
 
 
423
  const stepNumber = template.querySelector('.step-number');
424
  stepNumber.textContent = procedureCounter++;
425
 
 
426
  if (type === 'material') {
427
  setupMaterialBlock(template);
428
  } else if (type === 'personnel') {
 
433
  setupUploadArea(template);
434
  }
435
 
 
436
  template.querySelector('.remove-block').addEventListener('click', () => {
437
  if (confirm('Are you sure you want to remove this block?')) {
438
  template.remove();
 
441
  });
442
 
443
  template.querySelector('.edit-block').addEventListener('click', () => {
444
+ alert('Edit mode. Modify content directly.');
 
 
 
445
  });
446
 
 
447
  template.setAttribute('draggable', true);
448
  template.addEventListener('dragstart', (e) => {
449
  e.dataTransfer.setData('text/plain', 'move');
 
455
  template.classList.remove('dragging');
456
  });
457
 
 
458
  builder.appendChild(template);
459
  placeholder.style.display = 'none';
460
 
 
461
  blocks.push({ id, type, element: template });
462
  }
463
 
 
486
  }
487
 
488
  addButton.addEventListener('click', addMaterialItem);
489
+ addMaterialItem();
490
  }
491
 
492
  function setupPersonnelBlock(block) {
 
514
  }
515
 
516
  addButton.addEventListener('click', addPersonnelItem);
517
+ addPersonnelItem();
518
  }
519
 
520
  function setupChecklistBlock(block) {
 
536
  }
537
 
538
  addButton.addEventListener('click', addChecklistItem);
539
+ addChecklistItem();
540
  }
541
 
542
  function setupUploadArea(block) {
 
560
  }
561
  });
562
 
 
563
  area.addEventListener('drop', (e) => {
564
  e.preventDefault();
565
  const file = e.dataTransfer.files[0];
 
577
  });
578
  }
579
 
 
580
  function updateStepNumbers() {
581
  procedureCounter = 1;
582
  document.querySelectorAll('.procedure-block').forEach(block => {
 
587
  });
588
  }
589
 
 
590
  function setupEvents() {
 
591
  builder.addEventListener('dragover', (e) => {
592
  e.preventDefault();
593
  const afterElement = getDragAfterElement(builder, e.clientY);
 
599
  }
600
  });
601
 
 
602
  saveBtn.addEventListener('click', () => {
603
  const title = prompt('Enter procedure title:', 'New Procedure') || 'Untitled';
604
  const id = 'PRC-' + Date.now().toString().substr(-6).toUpperCase();
 
618
  })
619
  };
620
 
 
621
  let procedures = JSON.parse(localStorage.getItem('rigProcedures') || '[]');
622
  procedures.push(procedure);
623
  localStorage.setItem('rigProcedures', JSON.stringify(procedures));
 
626
  loadProcedures();
627
  });
628
 
 
629
  printBtn.addEventListener('click', () => {
630
  window.print();
631
  });
632
 
633
+ // Download as DOCX
634
  downloadWordBtn.addEventListener('click', () => {
635
+ const { Document, Paragraph, TextRun, ImageRun, Packer } = docx;
636
+
637
+ const blocks = document.querySelectorAll('.procedure-block');
638
+ const elements = [];
639
+
640
+ blocks.forEach(block => {
641
+ const type = block.querySelector('.text-sm').textContent.trim();
642
+
643
+ // Extract text content
644
+ let content = '';
645
+ const textarea = block.querySelector('textarea');
646
+ const inputs = block.querySelectorAll('input[type="text"], input[type="number"], select');
647
+ const timeInputs = block.querySelectorAll('input[type="time"]');
648
+ const checklist = block.querySelectorAll('.checklist-items input[type="checkbox"]');
649
+ const img = block.querySelector('img');
650
+
651
+ // Add step title
652
+ elements.push(new Paragraph({
653
+ children: [
654
+ new TextRun({
655
+ text: `Step ${block.querySelector('.step-number').textContent}: ${type}`,
656
+ bold: true,
657
+ size: 28
658
+ })
659
+ ],
660
+ spacing: { after: 100 }
661
+ }));
662
+
663
+ if (textarea && textarea.value) {
664
+ elements.push(new Paragraph({
665
+ children: [new TextRun(textarea.value)],
666
+ spacing: { after: 100 }
667
+ }));
668
+ }
669
+
670
+ if (inputs.length > 0) {
671
+ const tableRows = Array.from(inputs).reduce((rows, input, i, arr) => {
672
+ if (i % 3 === 0) rows.push([]);
673
+ const value = input.value || input.options?.[input.selectedIndex]?.text || '';
674
+ rows[rows.length - 1].push(value);
675
+ return rows;
676
+ }, []).map(row => {
677
+ return new docx.TableRow({
678
+ children: row.map(cell => {
679
+ return new docx.TableCell({
680
+ children: [new Paragraph(cell)],
681
+ width: { size: 33, type: docx.WidthType.PERCENTAGE }
682
+ });
683
+ })
684
+ });
685
+ });
686
+
687
+ if (tableRows.length > 0) {
688
+ elements.push(new docx.Table({
689
+ rows: tableRows,
690
+ width: { size: 100, type: docx.WidthType.PERCENTAGE }
691
+ }));
692
+ }
693
+ }
694
+
695
+ if (timeInputs.length > 1) {
696
+ const start = timeInputs[0].value;
697
+ const end = timeInputs[1].value;
698
+ elements.push(new Paragraph({
699
+ children: [new TextRun(`Duration: ${start} - ${end}`)],
700
+ spacing: { after: 100 }
701
+ }));
702
+ }
703
+
704
+ if (checklist.length > 0) {
705
+ Array.from(block.querySelectorAll('.checklist-items > div')).forEach(itemDiv => {
706
+ const checkbox = itemDiv.querySelector('input[type="checkbox"]');
707
+ const label = itemDiv.querySelector('input[type="text"]');
708
+ elements.push(new Paragraph({
709
+ children: [
710
+ new TextRun({
711
+ text: `[${checkbox.checked ? 'x' : ' '}] ${label.value}`,
712
+ size: 24
713
+ })
714
+ ]
715
+ }));
716
+ });
717
+ }
718
+
719
+ if (img && !img.classList.contains('hidden')) {
720
+ const imgData = img.src;
721
+ elements.push(new Paragraph({
722
+ children: [
723
+ new ImageRun({
724
+ data: atob(imgData.split(',')[1]),
725
+ transformation: {
726
+ width: 300,
727
+ height: 200
728
+ }
729
+ })
730
+ ],
731
+ spacing: { after: 100 }
732
+ }));
733
+ }
734
+
735
+ elements.push(new Paragraph({ spacing: { after: 100 } })); // spacer
736
+ });
737
+
738
+ const doc = new Document({
739
+ sections: [{
740
+ properties: {},
741
+ children: elements
742
+ }]
743
+ });
744
+
745
+ Packer.toBlob(doc).then(blob => {
746
+ saveAs(blob, 'Rig_Operation_Procedure.docx');
747
  });
748
  });
749
 
750
+ // Download as RTF (simplified RTF string)
751
+ downloadRTFBtn.addEventListener('click', () => {
752
+ let rtfContent = '{\\rtf1\\ansi\\deff0{\\fonttbl{\\f0 Times New Roman;}}\n';
753
+ rtfContent += '\\viewkind4\\uc1\\pard\\f0\\fs24\\b Rig Operation Procedure\\b0\\par\n';
754
+ rtfContent += '\\par\n';
755
+
756
+ document.querySelectorAll('.procedure-block').forEach(block => {
757
+ const stepNum = block.querySelector('.step-number').textContent;
758
+ const type = block.querySelector('.text-sm').textContent.trim();
759
+ rtfContent += `\\b Step ${stepNum}: ${type}\\b0\\par\n`;
760
+
761
+ const textarea = block.querySelector('textarea');
762
+ if (textarea && textarea.value) {
763
+ rtfContent += textarea.value.replace(/\n/g, '\\line ') + '\\par\n';
764
+ }
765
+
766
+ const timeInputs = block.querySelectorAll('input[type="time"]');
767
+ if (timeInputs.length === 2) {
768
+ const start = timeInputs[0].value;
769
+ const end = timeInputs[1].value;
770
+ rtfContent += `Duration: ${start} - ${end}\\par\n`;
771
+ }
772
+
773
+ block.querySelectorAll('.material-list > div').forEach(item => {
774
+ const name = item.querySelector('input[type="text"]')?.value || '';
775
+ const qty = item.querySelector('input[type="number"]')?.value || '';
776
+ const unit = item.querySelector('select')?.options?.[item.querySelector('select')?.selectedIndex]?.text || '';
777
+ if (name) rtfContent += `\\bullet\\t${qty} ${unit} of ${name}\\par\n`;
778
+ });
779
+
780
+ block.querySelectorAll('.personnel-list > div').forEach(item => {
781
+ const name = item.querySelector('input[type="text"]')?.value || '';
782
+ const role = item.querySelector('select')?.options?.[item.querySelector('select')?.selectedIndex]?.text || '';
783
+ if (name) rtfContent += `\\bullet\\t${name} (${role})\\par\n`;
784
+ });
785
+
786
+ block.querySelectorAll('.checklist-items > div').forEach(item => {
787
+ const label = item.querySelector('input[type="text"]')?.value || '';
788
+ const checked = item.querySelector('input[type="checkbox"]')?.checked ? 'x' : ' ';
789
+ rtfContent += `\\bullet\\t[${checked}] ${label}\\par\n`;
790
+ });
791
+
792
+ rtfContent += '\\par\n';
793
+ });
794
+
795
+ rtfContent += '}';
796
+
797
+ const blob = new Blob([rtfContent], { type: 'application/rtf' });
798
+ saveAs(blob, 'Rig_Operation_Procedure.rtf');
799
+ });
800
+
801
  approvalBtn.addEventListener('click', () => {
802
  if (blocks.length === 0) {
803
  alert('Please add at least one block before submitting.');
 
805
  }
806
  if (confirm('Submit this procedure for approval? It will be reviewed by the safety team.')) {
807
  const procedures = JSON.parse(localStorage.getItem('rigProcedures') || '[]');
 
808
  if (procedures.length > 0) {
809
  procedures[procedures.length - 1].status = 'Pending';
810
  localStorage.setItem('rigProcedures', JSON.stringify(procedures));
 
828
  }, { offset: Number.NEGATIVE_INFINITY }).element;
829
  }
830
 
 
831
  function loadProcedures() {
832
  const tableBody = document.getElementById('procedureTableBody');
833
  tableBody.innerHTML = '';
 
853
  tableBody.appendChild(tr);
854
  });
855
 
 
856
  document.querySelectorAll('.edit-proc').forEach(btn => {
857
  btn.addEventListener('click', (e) => {
858
  const id = e.target.dataset.id;
 
873
  const procedure = procedures.find(p => p.id === id);
874
  if (!procedure) return;
875
 
 
876
  builder.innerHTML = '';
877
  blocks = [];
878
  procedureCounter = 1;
879
 
 
880
  procedure.blocks.forEach(blockObj => {
881
  const div = document.createElement('div');
882
  div.innerHTML = blockObj.html;
883
  const block = div.firstElementChild;
884
  block.style.display = 'block';
885
 
 
886
  if (readOnly) {
887
  block.querySelectorAll('input, textarea, button').forEach(el => {
888
  if (el.type !== 'checkbox') {
 
894
  });
895
  block.removeAttribute('draggable');
896
  } else {
 
897
  block.querySelector('.remove-block').addEventListener('click', () => {
898
  if (confirm('Remove this block?')) {
899
  block.remove();
 
913
  updateStepNumbers();
914
  }
915
 
 
916
  window.addEventListener('DOMContentLoaded', init);
917
  </script>
918
 
 
919
  <style media="print">
920
  .toolbox, .toolbox-item, #placeholder, .edit-block, .remove-block {
921
  display: none !important;
prompts.txt CHANGED
@@ -1 +1,2 @@
1
- buatkan rig operation procedure seperti lego dimana di dalamnya terdapat inputing procedure dimana didalamnya terdapat upload gambar , waktu procedure, material yang di butuhkan , safety concern , personel dan informasi tambahan lainnya. penyusunan procedure ada juga tambahan editing untuk memastikan beberapa variable dapat di edit untuk nilai nilai tertentu , database procedure , approval review, document download ke word atau print
 
 
1
+ buatkan rig operation procedure seperti lego dimana di dalamnya terdapat inputing procedure dimana didalamnya terdapat upload gambar , waktu procedure, material yang di butuhkan , safety concern , personel dan informasi tambahan lainnya. penyusunan procedure ada juga tambahan editing untuk memastikan beberapa variable dapat di edit untuk nilai nilai tertentu , database procedure , approval review, document download ke word atau print
2
+ saat download word , pastikan format document dalam doc atau rtf