348 lines
18 KiB
HTML
348 lines
18 KiB
HTML
{% extends "base.html" %} {% block title %}Upload Patient Data - Report
|
|
Generator{% endblock %} {% block content %}
|
|
<div class="px-4 py-6 sm:px-0">
|
|
<div class="bg-white shadow rounded-lg">
|
|
<div class="px-4 py-5 sm:p-6">
|
|
<h2 class="text-2xl font-bold text-gray-900 mb-6">
|
|
Upload Patient Data and Files
|
|
</h2>
|
|
|
|
{% if error %}
|
|
<div class="bg-red-50 border border-red-200 rounded-lg p-4 mb-6">
|
|
<p class="text-red-800">{{ error }}</p>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<form
|
|
id="upload-form"
|
|
action="/upload"
|
|
method="post"
|
|
enctype="multipart/form-data"
|
|
class="space-y-6"
|
|
>
|
|
<!-- Patient Information Section -->
|
|
<div class="border-b border-gray-200 pb-6">
|
|
<h3 class="text-lg font-medium text-gray-900 mb-4">
|
|
Patient Information
|
|
</h3>
|
|
<div class="grid grid-cols-1 gap-6 sm:grid-cols-2">
|
|
<div>
|
|
<label
|
|
for="first_name"
|
|
class="block text-sm font-medium text-gray-700"
|
|
>First Name</label
|
|
>
|
|
<input
|
|
type="text"
|
|
name="first_name"
|
|
id="first_name"
|
|
required
|
|
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-3 py-2 border"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label
|
|
for="last_name"
|
|
class="block text-sm font-medium text-gray-700"
|
|
>Last Name</label
|
|
>
|
|
<input
|
|
type="text"
|
|
name="last_name"
|
|
id="last_name"
|
|
required
|
|
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-3 py-2 border"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label
|
|
for="age"
|
|
class="block text-sm font-medium text-gray-700"
|
|
>Age</label
|
|
>
|
|
<input
|
|
type="number"
|
|
name="age"
|
|
id="age"
|
|
required
|
|
min="1"
|
|
max="120"
|
|
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-3 py-2 border"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label
|
|
for="height"
|
|
class="block text-sm font-medium text-gray-700"
|
|
>Height (e.g., 5'4" or 165cm)</label
|
|
>
|
|
<input
|
|
type="text"
|
|
name="height"
|
|
id="height"
|
|
required
|
|
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-3 py-2 border"
|
|
placeholder="5'4""
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label
|
|
for="weight"
|
|
class="block text-sm font-medium text-gray-700"
|
|
>Weight (e.g., 123lbs or 56kg)</label
|
|
>
|
|
<input
|
|
type="text"
|
|
name="weight"
|
|
id="weight"
|
|
required
|
|
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-3 py-2 border"
|
|
placeholder="123lbs"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label
|
|
for="gender"
|
|
class="block text-sm font-medium text-gray-700"
|
|
>Gender</label
|
|
>
|
|
<select
|
|
name="gender"
|
|
id="gender"
|
|
required
|
|
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-3 py-2 border"
|
|
>
|
|
<option value="">Select...</option>
|
|
<option value="male">Male</option>
|
|
<option value="female">Female</option>
|
|
<option value="other">Other</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label
|
|
for="focus"
|
|
class="block text-sm font-medium text-gray-700"
|
|
>Training Focus</label
|
|
>
|
|
<input
|
|
type="text"
|
|
name="focus"
|
|
id="focus"
|
|
value="Endurance"
|
|
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-3 py-2 border"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label
|
|
for="session_id"
|
|
class="block text-sm font-medium text-gray-700"
|
|
>Session ID</label
|
|
>
|
|
<input
|
|
type="text"
|
|
name="session_id"
|
|
id="session_id"
|
|
value="default"
|
|
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-3 py-2 border"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label
|
|
class="block text-sm font-medium text-gray-700"
|
|
>Recommended Next Testing Date</label
|
|
>
|
|
<div class="mt-1 grid grid-cols-2 gap-3">
|
|
<select
|
|
id="next_testing_month"
|
|
required
|
|
class="block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-3 py-2 border"
|
|
>
|
|
<option value="">Month</option>
|
|
<option value="January">January</option>
|
|
<option value="February">February</option>
|
|
<option value="March">March</option>
|
|
<option value="April">April</option>
|
|
<option value="May">May</option>
|
|
<option value="June">June</option>
|
|
<option value="July">July</option>
|
|
<option value="August">August</option>
|
|
<option value="September">September</option>
|
|
<option value="October">October</option>
|
|
<option value="November">November</option>
|
|
<option value="December">December</option>
|
|
</select>
|
|
<select
|
|
id="next_testing_year"
|
|
required
|
|
class="block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-3 py-2 border"
|
|
>
|
|
<option value="">Year</option>
|
|
</select>
|
|
</div>
|
|
<input
|
|
type="hidden"
|
|
name="next_testing_date"
|
|
id="next_testing_date"
|
|
required
|
|
/>
|
|
</div>
|
|
<script>
|
|
// Populate year dropdown
|
|
(function () {
|
|
const yearSelect =
|
|
document.getElementById(
|
|
"next_testing_year"
|
|
);
|
|
const currentYear = new Date().getFullYear();
|
|
for (
|
|
let i = currentYear;
|
|
i <= currentYear + 10;
|
|
i++
|
|
) {
|
|
const option =
|
|
document.createElement("option");
|
|
option.value = i;
|
|
option.textContent = i;
|
|
yearSelect.appendChild(option);
|
|
}
|
|
|
|
// Combine month and year into hidden input
|
|
const monthSelect =
|
|
document.getElementById(
|
|
"next_testing_month"
|
|
);
|
|
const dateInput =
|
|
document.getElementById(
|
|
"next_testing_date"
|
|
);
|
|
|
|
function updateDateInput() {
|
|
const month = monthSelect.value;
|
|
const year = yearSelect.value;
|
|
if (month && year) {
|
|
dateInput.value = month + " " + year;
|
|
} else {
|
|
dateInput.value = "";
|
|
}
|
|
}
|
|
|
|
monthSelect.addEventListener(
|
|
"change",
|
|
updateDateInput
|
|
);
|
|
yearSelect.addEventListener(
|
|
"change",
|
|
updateDateInput
|
|
);
|
|
|
|
// Validate form submission
|
|
const form =
|
|
document.getElementById("upload-form");
|
|
form.addEventListener("submit", function (e) {
|
|
const month = monthSelect.value;
|
|
const year = yearSelect.value;
|
|
if (!month || !year) {
|
|
e.preventDefault();
|
|
alert(
|
|
"Please select both month and year for the recommended next testing date."
|
|
);
|
|
return false;
|
|
}
|
|
// Ensure hidden input is set before submission
|
|
updateDateInput();
|
|
});
|
|
})();
|
|
</script>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- File Upload Section -->
|
|
<div class="border-b border-gray-200 pb-6">
|
|
<h3 class="text-lg font-medium text-gray-900 mb-4">
|
|
Upload Files
|
|
</h3>
|
|
<div class="space-y-4">
|
|
<div>
|
|
<label
|
|
for="spirometry_pdf"
|
|
class="block text-sm font-medium text-gray-700"
|
|
>Spirometry PDF</label
|
|
>
|
|
<input
|
|
type="file"
|
|
name="spirometry_pdf"
|
|
id="spirometry_pdf"
|
|
accept=".pdf"
|
|
required
|
|
class="mt-1 block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-md file:border-0 file:text-sm file:font-semibold file:bg-indigo-50 file:text-indigo-700 hover:file:bg-indigo-100"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label
|
|
for="pnoe_csv"
|
|
class="block text-sm font-medium text-gray-700"
|
|
>Pnoe CSV</label
|
|
>
|
|
<input
|
|
type="file"
|
|
name="pnoe_csv"
|
|
id="pnoe_csv"
|
|
accept=".csv"
|
|
required
|
|
class="mt-1 block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-md file:border-0 file:text-sm file:font-semibold file:bg-indigo-50 file:text-indigo-700 hover:file:bg-indigo-100"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label
|
|
for="fat_percentage"
|
|
class="block text-sm font-medium text-gray-700"
|
|
>Body Fat Percentage (%)</label
|
|
>
|
|
<input
|
|
type="number"
|
|
step="0.1"
|
|
name="fat_percentage"
|
|
id="fat_percentage"
|
|
required
|
|
min="0"
|
|
max="100"
|
|
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-3 py-2 border"
|
|
placeholder="22.5"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label
|
|
for="oxygenation_csv"
|
|
class="block text-sm font-medium text-gray-700"
|
|
>Muscle Oxygenation CSV (Optional)</label
|
|
>
|
|
<input
|
|
type="file"
|
|
name="oxygenation_csv"
|
|
id="oxygenation_csv"
|
|
accept=".csv"
|
|
class="mt-1 block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-md file:border-0 file:text-sm file:font-semibold file:bg-indigo-50 file:text-indigo-700 hover:file:bg-indigo-100"
|
|
/>
|
|
<p class="mt-1 text-xs text-gray-500">
|
|
Upload NIRS muscle oxygen CSV file to generate
|
|
TSI graph
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Submit Button -->
|
|
<div class="flex justify-end">
|
|
<button
|
|
type="submit"
|
|
class="inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
|
>
|
|
Generate Report
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|