257 lines
12 KiB
HTML
257 lines
12 KiB
HTML
{% extends "layouts/base.html" %}
|
|
{% load i18n %}
|
|
{% load static %}
|
|
|
|
{% block title %}{% trans "Import Doctor Ratings" %} - PX360{% endblock %}
|
|
|
|
{% block extra_css %}
|
|
<style>
|
|
.field-label {
|
|
font-size: 10px;
|
|
font-weight: 700;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.05em;
|
|
color: #64748b;
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="p-8">
|
|
<!-- Header -->
|
|
<header class="mb-8">
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<h1 class="text-2xl font-bold text-navy flex items-center gap-3">
|
|
<div class="w-10 h-10 bg-yellow-100 rounded-xl flex items-center justify-center">
|
|
<i data-lucide="upload" class="w-5 h-5 text-yellow-600"></i>
|
|
</div>
|
|
{% trans "Import Doctor Ratings" %}
|
|
</h1>
|
|
<p class="text-slate mt-2 text-sm">{% trans "Import doctor ratings from HIS CSV export" %}</p>
|
|
</div>
|
|
<div>
|
|
<a href="{% url 'physicians:doctor_rating_job_list' %}"
|
|
class="px-5 py-2.5 border border-slate-200 text-slate rounded-xl font-semibold hover:bg-slate-50 hover:border-slate-300 transition flex items-center gap-2">
|
|
<i data-lucide="clock" class="w-4 h-4"></i>
|
|
{% trans "Import History" %}
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
|
<!-- Instructions & Form -->
|
|
<div class="lg:col-span-2 space-y-6">
|
|
<!-- Instructions Card -->
|
|
<section class="bg-white rounded-2xl shadow-sm border border-slate-100">
|
|
<div class="p-6 border-b border-slate-200">
|
|
<h3 class="text-lg font-bold text-navy flex items-center gap-2">
|
|
<i data-lucide="info" class="w-5 h-5 text-blue"></i>
|
|
{% trans "Instructions" %}
|
|
</h3>
|
|
</div>
|
|
<div class="p-6">
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<div>
|
|
<h4 class="font-bold text-navy mb-3">{% trans "Expected CSV Format:" %}</h4>
|
|
<p class="text-slate text-sm mb-3">
|
|
{% trans "Upload Doctor Rating Report CSV from your HIS system." %}
|
|
</p>
|
|
<ul class="space-y-2">
|
|
<li class="flex items-start gap-2 text-sm text-slate">
|
|
<i data-lucide="check-circle" class="w-4 h-4 text-green-600 mt-0.5 flex-shrink-0"></i>
|
|
{% trans "Header rows are automatically skipped" %}
|
|
</li>
|
|
<li class="flex items-start gap-2 text-sm text-slate">
|
|
<i data-lucide="check-circle" class="w-4 h-4 text-green-600 mt-0.5 flex-shrink-0"></i>
|
|
{% trans "Department headers are detected automatically" %}
|
|
</li>
|
|
<li class="flex items-start gap-2 text-sm text-slate">
|
|
<i data-lucide="check-circle" class="w-4 h-4 text-green-600 mt-0.5 flex-shrink-0"></i>
|
|
{% trans "Doctor IDs are extracted from names like '10738-NAME'" %}
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div>
|
|
<h4 class="font-bold text-navy mb-3">{% trans "Required Columns:" %}</h4>
|
|
<ul class="space-y-2">
|
|
<li class="flex items-start gap-2 text-sm text-slate">
|
|
<i data-lucide="asterisk" class="w-4 h-4 text-red-600 mt-0.5 flex-shrink-0"></i>
|
|
<span><strong class="text-navy">UHID</strong> - {% trans "Patient MRN" %}</span>
|
|
</li>
|
|
<li class="flex items-start gap-2 text-sm text-slate">
|
|
<i data-lucide="asterisk" class="w-4 h-4 text-red-600 mt-0.5 flex-shrink-0"></i>
|
|
<span><strong class="text-navy">Doctor Name</strong> - {% trans "With or without ID prefix" %}</span>
|
|
</li>
|
|
<li class="flex items-start gap-2 text-sm text-slate">
|
|
<i data-lucide="asterisk" class="w-4 h-4 text-red-600 mt-0.5 flex-shrink-0"></i>
|
|
<span><strong class="text-navy">Rating</strong> - {% trans "1-5 rating value" %}</span>
|
|
</li>
|
|
<li class="flex items-start gap-2 text-sm text-slate">
|
|
<i data-lucide="circle" class="w-4 h-4 text-slate-400 mt-0.5 flex-shrink-0"></i>
|
|
<span><strong class="text-navy">Patient Name, Rating Date</strong> - {% trans "Optional" %}</span>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Import Form -->
|
|
<section class="bg-white rounded-2xl shadow-sm border border-slate-100">
|
|
<div class="p-6 border-b border-slate-200">
|
|
<h3 class="text-lg font-bold text-navy">{% trans "Upload CSV File" %}</h3>
|
|
</div>
|
|
<div class="p-6">
|
|
<form method="post" enctype="multipart/form-data" class="space-y-6">
|
|
{% csrf_token %}
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<div>
|
|
<label for="{{ form.hospital.id_for_label }}" class="field-label block mb-2">
|
|
{% trans "Hospital" %} <span class="text-red-600">*</span>
|
|
</label>
|
|
{{ form.hospital }}
|
|
{% if form.hospital.errors %}
|
|
<div class="text-red-600 text-sm mt-1">{{ form.hospital.errors.0 }}</div>
|
|
{% endif %}
|
|
<p class="text-slate text-xs mt-1">{% trans "Select hospital these ratings belong to" %}</p>
|
|
</div>
|
|
|
|
<div>
|
|
<label for="{{ form.skip_header_rows.id_for_label }}" class="field-label block mb-2">
|
|
{% trans "Skip Header Rows" %}
|
|
</label>
|
|
{{ form.skip_header_rows }}
|
|
{% if form.skip_header_rows.errors %}
|
|
<div class="text-red-600 text-sm mt-1">{{ form.skip_header_rows.errors.0 }}</div>
|
|
{% endif %}
|
|
<p class="text-slate text-xs mt-1">
|
|
{% trans "Default is 6 rows (Doctor Rating Report format)" %}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<label for="{{ form.csv_file.id_for_label }}" class="field-label block mb-2">
|
|
{% trans "CSV File" %} <span class="text-red-600">*</span>
|
|
</label>
|
|
<div class="relative">
|
|
<div class="border-2 border-dashed border-slate-300 rounded-xl p-8 text-center hover:border-blue transition">
|
|
<div class="w-16 h-16 bg-blue/10 rounded-full flex items-center justify-center mx-auto mb-4">
|
|
<i data-lucide="file-csv" class="w-8 h-8 text-blue"></i>
|
|
</div>
|
|
<p class="text-slate font-medium mb-2">{% trans "Drag and drop your CSV file here" %}</p>
|
|
<p class="text-slate text-sm mb-4">{% trans "or click to browse" %}</p>
|
|
{{ form.csv_file }}
|
|
</div>
|
|
</div>
|
|
{% if form.csv_file.errors %}
|
|
<div class="text-red-600 text-sm mt-1">{{ form.csv_file.errors.0 }}</div>
|
|
{% endif %}
|
|
<p class="text-slate text-xs mt-2">
|
|
<i data-lucide="info" class="w-3 h-3 inline mr-1"></i>
|
|
{% trans "Maximum file size: 10MB. Only .csv files accepted." %}
|
|
</p>
|
|
</div>
|
|
|
|
<div class="flex items-center gap-3 pt-4 border-t border-slate-200">
|
|
<button type="submit" class="px-6 py-2.5 bg-navy text-white rounded-xl font-semibold shadow-md hover:bg-blue transition flex items-center gap-2">
|
|
<i data-lucide="upload" class="w-4 h-4"></i>
|
|
{% trans "Upload & Preview" %}
|
|
</button>
|
|
<a href="{% url 'physicians:physician_list' %}" class="px-6 py-2.5 border border-slate-200 text-slate rounded-xl font-semibold hover:bg-slate-50 hover:border-slate-300 transition flex items-center gap-2">
|
|
<i data-lucide="x-circle" class="w-4 h-4"></i>
|
|
{% trans "Cancel" %}
|
|
</a>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
|
|
<!-- API Integration Info -->
|
|
<div class="lg:col-span-1">
|
|
<section class="bg-white rounded-2xl shadow-sm border border-slate-100 sticky top-8">
|
|
<div class="p-6 border-b border-slate-200">
|
|
<h3 class="text-lg font-bold text-navy flex items-center gap-2">
|
|
<i data-lucide="code" class="w-5 h-5 text-blue"></i>
|
|
{% trans "API Integration" %}
|
|
</h3>
|
|
</div>
|
|
<div class="p-6">
|
|
<p class="text-slate text-sm mb-4">
|
|
{% trans "You can also integrate directly with your HIS system using our API:" %}
|
|
</p>
|
|
<div class="bg-slate-900 text-white p-4 rounded-xl font-mono text-sm space-y-2 mb-4">
|
|
<div class="text-green-400">POST /api/physicians/ratings/his/</div>
|
|
<div class="text-slate-400 text-xs mt-2">{% trans "# Or for single ratings:" %}</div>
|
|
<div class="text-green-400">POST /api/physicians/ratings/import/single/</div>
|
|
</div>
|
|
<p class="text-slate text-sm">
|
|
<i data-lucide="info" class="w-4 h-4 inline mr-1 text-blue"></i>
|
|
{% trans "See API documentation for more details." %}
|
|
</p>
|
|
<a href="/api/docs/" target="_blank"
|
|
class="inline-flex items-center gap-2 mt-3 text-blue font-semibold text-sm hover:text-navy transition">
|
|
{% trans "View API Docs" %}
|
|
<i data-lucide="external-link" class="w-3 h-3"></i>
|
|
</a>
|
|
</div>
|
|
|
|
<!-- Quick Tips -->
|
|
<div class="p-6 border-t border-slate-200">
|
|
<h4 class="font-bold text-navy mb-3 flex items-center gap-2">
|
|
<i data-lucide="lightbulb" class="w-4 h-4 text-yellow-600"></i>
|
|
{% trans "Quick Tips" %}
|
|
</h4>
|
|
<ul class="space-y-3">
|
|
<li class="flex items-start gap-2 text-sm text-slate">
|
|
<i data-lucide="check" class="w-4 h-4 text-green-600 mt-0.5 flex-shrink-0"></i>
|
|
{% trans "Ensure CSV is exported with UTF-8 encoding" %}
|
|
</li>
|
|
<li class="flex items-start gap-2 text-sm text-slate">
|
|
<i data-lucide="check" class="w-4 h-4 text-green-600 mt-0.5 flex-shrink-0"></i>
|
|
{% trans "Verify doctor IDs match PX360 records" %}
|
|
</li>
|
|
<li class="flex items-start gap-2 text-sm text-slate">
|
|
<i data-lucide="check" class="w-4 h-4 text-green-600 mt-0.5 flex-shrink-0"></i>
|
|
{% trans "Ratings outside 1-5 range will be skipped" %}
|
|
</li>
|
|
<li class="flex items-start gap-2 text-sm text-slate">
|
|
<i data-lucide="check" class="w-4 h-4 text-green-600 mt-0.5 flex-shrink-0"></i>
|
|
{% trans "Duplicate ratings for same patient/doctor are ignored" %}
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block extra_js %}
|
|
<script>
|
|
lucide.createIcons();
|
|
|
|
// Add Tailwind classes to form inputs
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const hospitalSelect = document.getElementById('{{ form.hospital.id_for_label }}');
|
|
const skipHeaderInput = document.getElementById('{{ form.skip_header_rows.id_for_label }}');
|
|
const csvFileInput = document.getElementById('{{ form.csv_file.id_for_label }}');
|
|
|
|
if (hospitalSelect) {
|
|
hospitalSelect.className = 'w-full px-4 py-2.5 border border-slate-200 rounded-xl text-sm focus:ring-2 focus:ring-navy/20 focus:border-navy outline-none transition';
|
|
}
|
|
|
|
if (skipHeaderInput) {
|
|
skipHeaderInput.className = 'w-full px-4 py-2.5 border border-slate-200 rounded-xl text-sm focus:ring-2 focus:ring-navy/20 focus:border-navy outline-none transition';
|
|
}
|
|
|
|
if (csvFileInput) {
|
|
csvFileInput.className = 'absolute inset-0 w-full h-full opacity-0 cursor-pointer';
|
|
}
|
|
});
|
|
</script>
|
|
{% endblock %} |