893 lines
40 KiB
HTML
893 lines
40 KiB
HTML
{% extends 'base.html' %}
|
|
{% load static %}
|
|
|
|
{% block title %}Data Export{% endblock %}
|
|
|
|
{% block css %}
|
|
<link href="{% static 'assets/plugins/select2/dist/css/select2.min.css' %}" rel="stylesheet" />
|
|
<link href="{% static 'assets/plugins/daterangepicker/daterangepicker.css' %}" rel="stylesheet" />
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div id="content" class="app-content">
|
|
<div class="container">
|
|
<ul class="breadcrumb">
|
|
<li class="breadcrumb-item"><a href="{% url 'core:dashboard' %}">Dashboard</a></li>
|
|
<li class="breadcrumb-item active">Data Export</li>
|
|
</ul>
|
|
|
|
<div class="row align-items-center mb-3">
|
|
<div class="col">
|
|
<h1 class="page-header">Data Export</h1>
|
|
<p class="text-muted">Export system data in various formats</p>
|
|
</div>
|
|
<div class="col-auto">
|
|
<div class="btn-group">
|
|
<button type="button" class="btn btn-outline-primary" onclick="showExportHistory()">
|
|
<i class="fa fa-history me-2"></i>Export History
|
|
</button>
|
|
<button type="button" class="btn btn-outline-info" onclick="showScheduledExports()">
|
|
<i class="fa fa-clock me-2"></i>Scheduled Exports
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Export Configuration -->
|
|
<div class="row">
|
|
<div class="col-md-8">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title">Configure Export</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
<form id="exportForm">
|
|
{% csrf_token %}
|
|
|
|
<!-- Data Source Selection -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-6">
|
|
<label class="form-label">Data Source</label>
|
|
<select name="data_source" class="form-select" required>
|
|
<option value="">Select data source</option>
|
|
<option value="patients">Patients</option>
|
|
<option value="appointments">Appointments</option>
|
|
<option value="billing">Billing Records</option>
|
|
<option value="laboratory">Laboratory Results</option>
|
|
<option value="radiology">Radiology Reports</option>
|
|
<option value="pharmacy">Pharmacy Records</option>
|
|
<option value="inpatients">Inpatient Records</option>
|
|
<option value="inventory">Inventory</option>
|
|
<option value="hr">HR Records</option>
|
|
<option value="users">User Accounts</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label">Export Format</label>
|
|
<select name="export_format" class="form-select" required>
|
|
<option value="">Select format</option>
|
|
<option value="csv">CSV (Comma Separated Values)</option>
|
|
<option value="xlsx">Excel (XLSX)</option>
|
|
<option value="pdf">PDF Report</option>
|
|
<option value="json">JSON</option>
|
|
<option value="xml">XML</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Date Range -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-6">
|
|
<label class="form-label">Date Range</label>
|
|
<input type="text" name="date_range" class="form-control" placeholder="Select date range">
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label">Record Limit</label>
|
|
<select name="record_limit" class="form-select">
|
|
<option value="">No limit</option>
|
|
<option value="100">100 records</option>
|
|
<option value="500">500 records</option>
|
|
<option value="1000">1,000 records</option>
|
|
<option value="5000">5,000 records</option>
|
|
<option value="10000">10,000 records</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Field Selection -->
|
|
<div class="mb-4">
|
|
<label class="form-label">Fields to Export</label>
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="select_all_fields" id="selectAllFields">
|
|
<label class="form-check-label fw-bold" for="selectAllFields">
|
|
Select All Fields
|
|
</label>
|
|
</div>
|
|
<hr>
|
|
<div id="availableFields">
|
|
<!-- Fields will be populated dynamically -->
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label">Selected Fields</label>
|
|
<div id="selectedFields" class="border rounded p-3" style="min-height: 200px;">
|
|
<p class="text-muted">Select fields from the left to include in export</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Filters -->
|
|
<div class="mb-4">
|
|
<label class="form-label">Filters</label>
|
|
<div id="filterContainer">
|
|
<div class="filter-group mb-2">
|
|
<div class="row">
|
|
<div class="col-md-3">
|
|
<select name="filter_field[]" class="form-select filter-field">
|
|
<option value="">Select field</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<select name="filter_operator[]" class="form-select">
|
|
<option value="equals">Equals</option>
|
|
<option value="not_equals">Not equals</option>
|
|
<option value="contains">Contains</option>
|
|
<option value="not_contains">Not contains</option>
|
|
<option value="starts_with">Starts with</option>
|
|
<option value="ends_with">Ends with</option>
|
|
<option value="greater_than">Greater than</option>
|
|
<option value="less_than">Less than</option>
|
|
<option value="is_null">Is empty</option>
|
|
<option value="is_not_null">Is not empty</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-5">
|
|
<input type="text" name="filter_value[]" class="form-control" placeholder="Filter value">
|
|
</div>
|
|
<div class="col-md-2">
|
|
<button type="button" class="btn btn-outline-danger btn-sm" onclick="removeFilter(this)">
|
|
<i class="fa fa-trash"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<button type="button" class="btn btn-outline-primary btn-sm" onclick="addFilter()">
|
|
<i class="fa fa-plus me-2"></i>Add Filter
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Export Options -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-6">
|
|
<label class="form-label">Export Options</label>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="include_headers" checked>
|
|
<label class="form-check-label">Include column headers</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="include_metadata">
|
|
<label class="form-check-label">Include metadata</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="compress_file">
|
|
<label class="form-check-label">Compress file (ZIP)</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="email_export">
|
|
<label class="form-check-label">Email export when ready</label>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label">Sort Options</label>
|
|
<div class="row">
|
|
<div class="col-md-8">
|
|
<select name="sort_field" class="form-select">
|
|
<option value="">No sorting</option>
|
|
<option value="id">ID</option>
|
|
<option value="created_at">Date Created</option>
|
|
<option value="updated_at">Date Modified</option>
|
|
<option value="name">Name</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<select name="sort_direction" class="form-select">
|
|
<option value="asc">Ascending</option>
|
|
<option value="desc">Descending</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Schedule Options -->
|
|
<div class="mb-4">
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="schedule_export" id="scheduleExport">
|
|
<label class="form-check-label fw-bold" for="scheduleExport">
|
|
Schedule this export
|
|
</label>
|
|
</div>
|
|
|
|
<div id="scheduleOptions" class="mt-3" style="display: none;">
|
|
<div class="row">
|
|
<div class="col-md-4">
|
|
<label class="form-label">Frequency</label>
|
|
<select name="schedule_frequency" class="form-select">
|
|
<option value="daily">Daily</option>
|
|
<option value="weekly">Weekly</option>
|
|
<option value="monthly">Monthly</option>
|
|
<option value="quarterly">Quarterly</option>
|
|
<option value="yearly">Yearly</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<label class="form-label">Start Date</label>
|
|
<input type="date" name="schedule_start_date" class="form-control">
|
|
</div>
|
|
<div class="col-md-4">
|
|
<label class="form-label">Time</label>
|
|
<input type="time" name="schedule_time" class="form-control" value="09:00">
|
|
</div>
|
|
</div>
|
|
<div class="row mt-3">
|
|
<div class="col-md-12">
|
|
<label class="form-label">Email Recipients</label>
|
|
<input type="email" name="schedule_recipients" class="form-control"
|
|
placeholder="Enter email addresses separated by commas">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Action Buttons -->
|
|
<div class="d-flex justify-content-between">
|
|
<div>
|
|
<button type="button" class="btn btn-outline-info" onclick="previewExport()">
|
|
<i class="fa fa-eye me-2"></i>Preview
|
|
</button>
|
|
<button type="button" class="btn btn-outline-warning" onclick="validateExport()">
|
|
<i class="fa fa-check me-2"></i>Validate
|
|
</button>
|
|
</div>
|
|
<div>
|
|
<button type="button" class="btn btn-secondary" onclick="resetForm()">
|
|
<i class="fa fa-times me-2"></i>Reset
|
|
</button>
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="fa fa-download me-2"></i>Export Data
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-4">
|
|
<!-- Export Summary -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="card-title">Export Summary</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="mb-3">
|
|
<label class="text-muted small">Data Source:</label>
|
|
<div id="summaryDataSource" class="fw-bold">Not selected</div>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="text-muted small">Format:</label>
|
|
<div id="summaryFormat" class="fw-bold">Not selected</div>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="text-muted small">Estimated Records:</label>
|
|
<div id="summaryRecords" class="fw-bold">-</div>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="text-muted small">Selected Fields:</label>
|
|
<div id="summaryFields" class="fw-bold">0</div>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="text-muted small">Filters Applied:</label>
|
|
<div id="summaryFilters" class="fw-bold">0</div>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="text-muted small">Estimated Size:</label>
|
|
<div id="summarySize" class="fw-bold">-</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Quick Export Templates -->
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title">Quick Export Templates</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="d-grid gap-2">
|
|
<button type="button" class="btn btn-outline-primary btn-sm" onclick="loadTemplate('patient_list')">
|
|
<i class="fa fa-users me-2"></i>Patient List
|
|
</button>
|
|
<button type="button" class="btn btn-outline-success btn-sm" onclick="loadTemplate('appointment_report')">
|
|
<i class="fa fa-calendar me-2"></i>Appointment Report
|
|
</button>
|
|
<button type="button" class="btn btn-outline-warning btn-sm" onclick="loadTemplate('billing_summary')">
|
|
<i class="fa fa-dollar-sign me-2"></i>Billing Summary
|
|
</button>
|
|
<button type="button" class="btn btn-outline-info btn-sm" onclick="loadTemplate('lab_results')">
|
|
<i class="fa fa-flask me-2"></i>Lab Results
|
|
</button>
|
|
<button type="button" class="btn btn-outline-secondary btn-sm" onclick="loadTemplate('inventory_report')">
|
|
<i class="fa fa-boxes me-2"></i>Inventory Report
|
|
</button>
|
|
</div>
|
|
|
|
<hr>
|
|
|
|
<div class="text-center">
|
|
<button type="button" class="btn btn-outline-primary btn-sm" onclick="saveAsTemplate()">
|
|
<i class="fa fa-save me-2"></i>Save as Template
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Export Progress -->
|
|
<div id="exportProgress" class="card mt-4" style="display: none;">
|
|
<div class="card-header">
|
|
<h4 class="card-title">Export Progress</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="mb-3">
|
|
<div class="d-flex justify-content-between mb-1">
|
|
<span>Exporting data...</span>
|
|
<span id="progressText">0%</span>
|
|
</div>
|
|
<div class="progress">
|
|
<div id="progressBar" class="progress-bar" role="progressbar" style="width: 0%"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row text-center">
|
|
<div class="col-md-4">
|
|
<div class="fs-24px fw-600 text-primary" id="exportedCount">0</div>
|
|
<div class="text-muted small">Records Exported</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="fs-24px fw-600 text-info" id="remainingCount">0</div>
|
|
<div class="text-muted small">Remaining</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="fs-24px fw-600 text-success" id="fileSizeCount">0 KB</div>
|
|
<div class="text-muted small">File Size</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-3 text-center">
|
|
<button type="button" class="btn btn-outline-danger" onclick="cancelExport()">
|
|
<i class="fa fa-stop me-2"></i>Cancel Export
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Export History Modal -->
|
|
<div class="modal fade" id="exportHistoryModal" tabindex="-1">
|
|
<div class="modal-dialog modal-xl">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">Export History</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="table-responsive">
|
|
<table class="table table-striped">
|
|
<thead>
|
|
<tr>
|
|
<th>Date</th>
|
|
<th>Data Source</th>
|
|
<th>Format</th>
|
|
<th>Records</th>
|
|
<th>Size</th>
|
|
<th>Status</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="historyTableBody">
|
|
<!-- History will be loaded here -->
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Preview Modal -->
|
|
<div class="modal fade" id="previewModal" tabindex="-1">
|
|
<div class="modal-dialog modal-xl">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">Export Preview</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div id="previewContent">
|
|
<!-- Preview will be loaded here -->
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
|
<button type="button" class="btn btn-primary" onclick="proceedWithExport()">Proceed with Export</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Save Template Modal -->
|
|
<div class="modal fade" id="saveTemplateModal" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">Save Export Template</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<form id="saveTemplateForm">
|
|
<div class="modal-body">
|
|
{% csrf_token %}
|
|
<div class="mb-3">
|
|
<label class="form-label">Template Name</label>
|
|
<input type="text" name="template_name" class="form-control" required>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label">Description</label>
|
|
<textarea name="template_description" class="form-control" rows="3"></textarea>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="is_public">
|
|
<label class="form-check-label">Make template available to other users</label>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
|
<button type="submit" class="btn btn-primary">Save Template</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block js %}
|
|
<script src="{% static 'assets/plugins/select2/dist/js/select2.min.js' %}"></script>
|
|
<script src="{% static 'assets/plugins/moment/moment.min.js' %}"></script>
|
|
<script src="{% static 'assets/plugins/daterangepicker/daterangepicker.js' %}"></script>
|
|
|
|
<script>
|
|
var exportId = null;
|
|
|
|
$(document).ready(function() {
|
|
// Initialize date range picker
|
|
$('input[name="date_range"]').daterangepicker({
|
|
autoUpdateInput: false,
|
|
locale: {
|
|
cancelLabel: 'Clear'
|
|
}
|
|
});
|
|
|
|
$('input[name="date_range"]').on('apply.daterangepicker', function(ev, picker) {
|
|
$(this).val(picker.startDate.format('MM/DD/YYYY') + ' - ' + picker.endDate.format('MM/DD/YYYY'));
|
|
updateSummary();
|
|
});
|
|
|
|
$('input[name="date_range"]').on('cancel.daterangepicker', function(ev, picker) {
|
|
$(this).val('');
|
|
updateSummary();
|
|
});
|
|
|
|
// Initialize Select2
|
|
$('.form-select').select2();
|
|
|
|
// Form change handlers
|
|
$('select[name="data_source"]').change(function() {
|
|
loadAvailableFields();
|
|
updateSummary();
|
|
});
|
|
|
|
$('select[name="export_format"]').change(function() {
|
|
updateSummary();
|
|
});
|
|
|
|
$('#scheduleExport').change(function() {
|
|
$('#scheduleOptions').toggle(this.checked);
|
|
});
|
|
|
|
$('#selectAllFields').change(function() {
|
|
$('.field-checkbox').prop('checked', this.checked);
|
|
updateSelectedFields();
|
|
});
|
|
|
|
// Form submission
|
|
$('#exportForm').submit(function(e) {
|
|
e.preventDefault();
|
|
startExport();
|
|
});
|
|
|
|
// Save template form
|
|
$('#saveTemplateForm').submit(function(e) {
|
|
e.preventDefault();
|
|
saveTemplate();
|
|
});
|
|
});
|
|
|
|
function loadAvailableFields() {
|
|
var dataSource = $('select[name="data_source"]').val();
|
|
if (!dataSource) return;
|
|
|
|
$.get('{% url "core:get_export_fields" %}', {data_source: dataSource}, function(data) {
|
|
var fieldsHtml = '';
|
|
data.fields.forEach(function(field) {
|
|
fieldsHtml += '<div class="form-check">' +
|
|
'<input class="form-check-input field-checkbox" type="checkbox" name="export_fields" value="' + field.name + '" id="field_' + field.name + '">' +
|
|
'<label class="form-check-label" for="field_' + field.name + '">' +
|
|
field.label + ' <small class="text-muted">(' + field.type + ')</small>' +
|
|
'</label>' +
|
|
'</div>';
|
|
});
|
|
|
|
$('#availableFields').html(fieldsHtml);
|
|
|
|
// Update filter field options
|
|
var filterOptions = '<option value="">Select field</option>';
|
|
data.fields.forEach(function(field) {
|
|
filterOptions += '<option value="' + field.name + '">' + field.label + '</option>';
|
|
});
|
|
$('.filter-field').html(filterOptions);
|
|
|
|
// Add change handler for field checkboxes
|
|
$('.field-checkbox').change(function() {
|
|
updateSelectedFields();
|
|
});
|
|
});
|
|
}
|
|
|
|
function updateSelectedFields() {
|
|
var selectedFields = [];
|
|
$('.field-checkbox:checked').each(function() {
|
|
var label = $(this).next('label').text();
|
|
selectedFields.push(label);
|
|
});
|
|
|
|
if (selectedFields.length > 0) {
|
|
var fieldsHtml = '<ul class="list-unstyled">';
|
|
selectedFields.forEach(function(field) {
|
|
fieldsHtml += '<li><i class="fa fa-check text-success me-2"></i>' + field + '</li>';
|
|
});
|
|
fieldsHtml += '</ul>';
|
|
$('#selectedFields').html(fieldsHtml);
|
|
} else {
|
|
$('#selectedFields').html('<p class="text-muted">Select fields from the left to include in export</p>');
|
|
}
|
|
|
|
updateSummary();
|
|
}
|
|
|
|
function addFilter() {
|
|
var filterHtml = '<div class="filter-group mb-2">' +
|
|
'<div class="row">' +
|
|
'<div class="col-md-3">' +
|
|
'<select name="filter_field[]" class="form-select filter-field">' +
|
|
$('.filter-field').first().html() +
|
|
'</select>' +
|
|
'</div>' +
|
|
'<div class="col-md-2">' +
|
|
'<select name="filter_operator[]" class="form-select">' +
|
|
'<option value="equals">Equals</option>' +
|
|
'<option value="not_equals">Not equals</option>' +
|
|
'<option value="contains">Contains</option>' +
|
|
'<option value="not_contains">Not contains</option>' +
|
|
'<option value="starts_with">Starts with</option>' +
|
|
'<option value="ends_with">Ends with</option>' +
|
|
'<option value="greater_than">Greater than</option>' +
|
|
'<option value="less_than">Less than</option>' +
|
|
'<option value="is_null">Is empty</option>' +
|
|
'<option value="is_not_null">Is not empty</option>' +
|
|
'</select>' +
|
|
'</div>' +
|
|
'<div class="col-md-5">' +
|
|
'<input type="text" name="filter_value[]" class="form-control" placeholder="Filter value">' +
|
|
'</div>' +
|
|
'<div class="col-md-2">' +
|
|
'<button type="button" class="btn btn-outline-danger btn-sm" onclick="removeFilter(this)">' +
|
|
'<i class="fa fa-trash"></i>' +
|
|
'</button>' +
|
|
'</div>' +
|
|
'</div>' +
|
|
'</div>';
|
|
|
|
$('#filterContainer').append(filterHtml);
|
|
updateSummary();
|
|
}
|
|
|
|
function removeFilter(button) {
|
|
$(button).closest('.filter-group').remove();
|
|
updateSummary();
|
|
}
|
|
|
|
function updateSummary() {
|
|
var dataSource = $('select[name="data_source"]').val();
|
|
var format = $('select[name="export_format"]').val();
|
|
var selectedFieldsCount = $('.field-checkbox:checked').length;
|
|
var filtersCount = $('.filter-group').length;
|
|
|
|
$('#summaryDataSource').text(dataSource ? $('select[name="data_source"] option:selected').text() : 'Not selected');
|
|
$('#summaryFormat').text(format ? format.toUpperCase() : 'Not selected');
|
|
$('#summaryFields').text(selectedFieldsCount);
|
|
$('#summaryFilters').text(filtersCount);
|
|
|
|
// Estimate record count and file size
|
|
if (dataSource && selectedFieldsCount > 0) {
|
|
var formData = new FormData($('#exportForm')[0]);
|
|
formData.append('estimate_only', 'true');
|
|
|
|
$.post('{% url "core:estimate_export" %}', formData, function(data) {
|
|
$('#summaryRecords').text(data.estimated_records.toLocaleString());
|
|
$('#summarySize').text(data.estimated_size);
|
|
}).fail(function() {
|
|
$('#summaryRecords').text('-');
|
|
$('#summarySize').text('-');
|
|
});
|
|
} else {
|
|
$('#summaryRecords').text('-');
|
|
$('#summarySize').text('-');
|
|
}
|
|
}
|
|
|
|
function previewExport() {
|
|
var formData = new FormData($('#exportForm')[0]);
|
|
formData.append('preview', 'true');
|
|
|
|
$.post('{% url "core:preview_export" %}', formData, function(data) {
|
|
$('#previewContent').html(data.preview_html);
|
|
$('#previewModal').modal('show');
|
|
}).fail(function() {
|
|
toastr.error('Failed to generate preview');
|
|
});
|
|
}
|
|
|
|
function validateExport() {
|
|
var formData = new FormData($('#exportForm')[0]);
|
|
formData.append('validate', 'true');
|
|
|
|
$.post('{% url "core:validate_export" %}', formData, function(data) {
|
|
if (data.valid) {
|
|
toastr.success('Export configuration is valid');
|
|
} else {
|
|
toastr.error('Validation failed: ' + data.errors.join(', '));
|
|
}
|
|
}).fail(function() {
|
|
toastr.error('Failed to validate export');
|
|
});
|
|
}
|
|
|
|
function startExport() {
|
|
var formData = new FormData($('#exportForm')[0]);
|
|
|
|
// Show progress section
|
|
$('#exportProgress').show();
|
|
|
|
// Start export
|
|
$.post('{% url "core:start_export" %}', formData, function(data) {
|
|
if (data.success) {
|
|
exportId = data.export_id;
|
|
monitorExport(exportId);
|
|
} else {
|
|
toastr.error('Failed to start export: ' + data.error);
|
|
$('#exportProgress').hide();
|
|
}
|
|
}).fail(function() {
|
|
toastr.error('Failed to start export');
|
|
$('#exportProgress').hide();
|
|
});
|
|
}
|
|
|
|
function monitorExport(exportId) {
|
|
var interval = setInterval(function() {
|
|
$.get('{% url "core:get_export_status" %}', {export_id: exportId}, function(data) {
|
|
updateExportProgress(data);
|
|
|
|
if (data.status === 'completed' || data.status === 'failed' || data.status === 'cancelled') {
|
|
clearInterval(interval);
|
|
showExportResults(data);
|
|
}
|
|
});
|
|
}, 2000);
|
|
}
|
|
|
|
function updateExportProgress(data) {
|
|
var percentage = Math.round((data.exported / data.total) * 100);
|
|
|
|
$('#progressBar').css('width', percentage + '%');
|
|
$('#progressText').text(percentage + '%');
|
|
|
|
$('#exportedCount').text(data.exported.toLocaleString());
|
|
$('#remainingCount').text((data.total - data.exported).toLocaleString());
|
|
$('#fileSizeCount').text(data.file_size);
|
|
}
|
|
|
|
function showExportResults(data) {
|
|
$('#exportProgress').hide();
|
|
|
|
if (data.status === 'completed') {
|
|
toastr.success('Export completed successfully');
|
|
|
|
// Provide download link
|
|
var downloadHtml = '<div class="alert alert-success">' +
|
|
'<h5>Export Completed</h5>' +
|
|
'<p>Your export has been completed successfully.</p>' +
|
|
'<a href="' + data.download_url + '" class="btn btn-primary">' +
|
|
'<i class="fa fa-download me-2"></i>Download File' +
|
|
'</a>' +
|
|
'</div>';
|
|
|
|
// Show download option
|
|
$('<div class="card mt-4"><div class="card-body">' + downloadHtml + '</div></div>').insertAfter('#exportProgress');
|
|
} else {
|
|
toastr.error('Export failed: ' + data.error);
|
|
}
|
|
}
|
|
|
|
function cancelExport() {
|
|
if (confirm('Are you sure you want to cancel this export?')) {
|
|
$.post('{% url "core:cancel_export" %}', {export_id: exportId}, function(data) {
|
|
if (data.success) {
|
|
toastr.success('Export cancelled');
|
|
$('#exportProgress').hide();
|
|
} else {
|
|
toastr.error('Failed to cancel export');
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
function loadTemplate(templateName) {
|
|
$.get('{% url "core:load_export_template" %}', {template: templateName}, function(data) {
|
|
// Populate form with template data
|
|
$('select[name="data_source"]').val(data.data_source).trigger('change');
|
|
$('select[name="export_format"]').val(data.export_format);
|
|
|
|
setTimeout(function() {
|
|
data.fields.forEach(function(field) {
|
|
$('#field_' + field).prop('checked', true);
|
|
});
|
|
updateSelectedFields();
|
|
}, 500);
|
|
|
|
toastr.success('Template loaded successfully');
|
|
}).fail(function() {
|
|
toastr.error('Failed to load template');
|
|
});
|
|
}
|
|
|
|
function saveAsTemplate() {
|
|
$('#saveTemplateModal').modal('show');
|
|
}
|
|
|
|
function saveTemplate() {
|
|
var formData = new FormData($('#saveTemplateForm')[0]);
|
|
|
|
// Add current export configuration
|
|
var exportConfig = {
|
|
data_source: $('select[name="data_source"]').val(),
|
|
export_format: $('select[name="export_format"]').val(),
|
|
fields: [],
|
|
filters: []
|
|
};
|
|
|
|
$('.field-checkbox:checked').each(function() {
|
|
exportConfig.fields.push($(this).val());
|
|
});
|
|
|
|
formData.append('export_config', JSON.stringify(exportConfig));
|
|
|
|
$.post('{% url "core:save_export_template" %}', formData, function(data) {
|
|
if (data.success) {
|
|
$('#saveTemplateModal').modal('hide');
|
|
toastr.success('Template saved successfully');
|
|
} else {
|
|
toastr.error('Failed to save template: ' + data.error);
|
|
}
|
|
}).fail(function() {
|
|
toastr.error('Failed to save template');
|
|
});
|
|
}
|
|
|
|
function showExportHistory() {
|
|
$.get('{% url "core:get_export_history" %}', function(data) {
|
|
var tbody = $('#historyTableBody');
|
|
tbody.empty();
|
|
|
|
data.exports.forEach(function(exp) {
|
|
var row = '<tr>' +
|
|
'<td>' + exp.date + '</td>' +
|
|
'<td>' + exp.data_source + '</td>' +
|
|
'<td>' + exp.format.toUpperCase() + '</td>' +
|
|
'<td>' + exp.record_count.toLocaleString() + '</td>' +
|
|
'<td>' + exp.file_size + '</td>' +
|
|
'<td><span class="badge bg-' + exp.status_color + '">' + exp.status + '</span></td>' +
|
|
'<td>' +
|
|
(exp.download_url ? '<a href="' + exp.download_url + '" class="btn btn-outline-primary btn-sm"><i class="fa fa-download"></i></a>' : '') +
|
|
'</td>' +
|
|
'</tr>';
|
|
tbody.append(row);
|
|
});
|
|
|
|
$('#exportHistoryModal').modal('show');
|
|
});
|
|
}
|
|
|
|
function showScheduledExports() {
|
|
// Implementation for scheduled exports
|
|
toastr.info('Scheduled exports feature coming soon');
|
|
}
|
|
|
|
function resetForm() {
|
|
$('#exportForm')[0].reset();
|
|
$('#selectedFields').html('<p class="text-muted">Select fields from the left to include in export</p>');
|
|
$('#availableFields').empty();
|
|
$('.filter-group').not(':first').remove();
|
|
updateSummary();
|
|
}
|
|
|
|
function proceedWithExport() {
|
|
$('#previewModal').modal('hide');
|
|
startExport();
|
|
}
|
|
</script>
|
|
|
|
<style>
|
|
.filter-group {
|
|
border: 1px solid #dee2e6;
|
|
border-radius: 4px;
|
|
padding: 10px;
|
|
background-color: #f8f9fa;
|
|
}
|
|
|
|
#selectedFields {
|
|
background-color: #f8f9fa;
|
|
}
|
|
|
|
.field-checkbox {
|
|
cursor: pointer;
|
|
}
|
|
|
|
.progress {
|
|
height: 20px;
|
|
}
|
|
|
|
#exportProgress .card-body {
|
|
min-height: 150px;
|
|
}
|
|
|
|
.form-check-label {
|
|
cursor: pointer;
|
|
}
|
|
|
|
.export-template-btn {
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.export-template-btn:hover {
|
|
transform: translateY(-1px);
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|