From 771bc31219a350a8248abf9203ee45568ed59972 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 29 Dec 2025 22:13:10 +0000
Subject: [PATCH 1/5] Initial plan
From 022dc73eb858df6dbf6aea2212cb46b76afe4f14 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 29 Dec 2025 22:16:21 +0000
Subject: [PATCH 2/5] Add GitHub Pages web application for DOZ3 report
generation
Co-authored-by: GraphSaf <63410676+GraphSaf@users.noreply.github.com>
---
.github/workflows/pages.yml | 38 ++++++
README.md | 59 ++++++++-
index.html | 106 +++++++++++++++
script.js | 229 ++++++++++++++++++++++++++++++++
styles.css | 251 ++++++++++++++++++++++++++++++++++++
5 files changed, 681 insertions(+), 2 deletions(-)
create mode 100644 .github/workflows/pages.yml
create mode 100644 index.html
create mode 100644 script.js
create mode 100644 styles.css
diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml
new file mode 100644
index 0000000..be1ad28
--- /dev/null
+++ b/.github/workflows/pages.yml
@@ -0,0 +1,38 @@
+name: Deploy to GitHub Pages
+
+on:
+ push:
+ branches:
+ - main
+ workflow_dispatch:
+
+permissions:
+ contents: read
+ pages: write
+ id-token: write
+
+concurrency:
+ group: "pages"
+ cancel-in-progress: false
+
+jobs:
+ deploy:
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Setup Pages
+ uses: actions/configure-pages@v4
+
+ - name: Upload artifact
+ uses: actions/upload-pages-artifact@v3
+ with:
+ path: '.'
+
+ - name: Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v4
diff --git a/README.md b/README.md
index 313a01e..8f82fc0 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,57 @@
-# xray
-Generate DOZ3 reports
+# X-Ray - DOZ3 Report Generator
+
+Веб-приложение для генерации отчетов ДОЗ-3 (регистрация доз облучения пациентов при рентгенологических исследованиях).
+
+## 🌐 GitHub Pages
+
+Приложение доступно онлайн: [https://graphsaf.github.io/xray/](https://graphsaf.github.io/xray/)
+
+## 📋 Описание
+
+X-Ray - это простое и удобное веб-приложение для создания отчетов ДОЗ-3, которое позволяет:
+
+- Заполнять данные пациента и обследования
+- Генерировать форматированные отчеты
+- Сохранять отчеты в формате HTML
+- Печатать отчеты
+
+## 🚀 Использование
+
+### Онлайн версия
+Просто откройте [https://graphsaf.github.io/xray/](https://graphsaf.github.io/xray/) в браузере.
+
+### Локальная версия
+1. Клонируйте репозиторий:
+```bash
+git clone https://github.com/GraphSaf/xray.git
+cd xray
+```
+
+2. Откройте `index.html` в браузере
+
+Приложение не требует установки дополнительных зависимостей - это статический HTML/CSS/JS сайт.
+
+## 📁 Структура проекта
+
+- `index.html` - главная страница приложения
+- `styles.css` - стили приложения
+- `script.js` - логика работы приложения
+- `ТЗ ДОЗ 3.pdf` - техническое задание
+
+## 🔧 Возможности
+
+- ✅ Заполнение данных пациента
+- ✅ Выбор типа обследования (флюорография, рентгенография, КТ, маммография)
+- ✅ Ввод дозы облучения
+- ✅ Генерация отчета
+- ✅ Скачивание отчета в HTML
+- ✅ Печать отчета
+- ✅ Адаптивный дизайн для мобильных устройств
+
+## 📄 Лицензия
+
+MIT License
+
+## 👤 Автор
+
+GraphSaf
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..219e7ce
--- /dev/null
+++ b/index.html
@@ -0,0 +1,106 @@
+
+
+
+
+
+ X-Ray - DOZ3 Report Generator
+
+
+
+
+
+ X-Ray DOZ3 Report Generator
+ Генератор отчетов ДОЗ-3
+
+
+
+
+
+
+ Сгенерированный отчет
+
+
+
+
+
+
+
+
+
+ Информация о ДОЗ-3
+ Форма ДОЗ-3 используется для регистрации и учета доз облучения пациентов при рентгенологических исследованиях.
+ Основные параметры:
+
+ - Данные пациента
+ - Тип и дата исследования
+ - Полученная доза облучения
+ - Область исследования
+ - Ответственный медицинский персонал
+
+
+
+
+
+
+
+
+
+
+
diff --git a/script.js b/script.js
new file mode 100644
index 0000000..31f65ee
--- /dev/null
+++ b/script.js
@@ -0,0 +1,229 @@
+// Report data storage
+let currentReport = null;
+
+// Form elements
+const reportForm = document.getElementById('reportForm');
+const clearFormBtn = document.getElementById('clearForm');
+const reportSection = document.getElementById('reportSection');
+const reportContent = document.getElementById('reportContent');
+const downloadBtn = document.getElementById('downloadBtn');
+const printBtn = document.getElementById('printBtn');
+const newReportBtn = document.getElementById('newReportBtn');
+
+// Initialize date input with today's date
+document.getElementById('examDate').valueAsDate = new Date();
+
+// Form submission handler
+reportForm.addEventListener('submit', function(e) {
+ e.preventDefault();
+
+ // Collect form data
+ const formData = new FormData(reportForm);
+ currentReport = {
+ patientName: formData.get('patientName'),
+ patientId: formData.get('patientId'),
+ examDate: formData.get('examDate'),
+ examType: formData.get('examType'),
+ examTypeLabel: getExamTypeLabel(formData.get('examType')),
+ dose: formData.get('dose'),
+ bodyPart: formData.get('bodyPart'),
+ doctor: formData.get('doctor'),
+ notes: formData.get('notes'),
+ generatedDate: new Date().toLocaleString('ru-RU')
+ };
+
+ // Generate and display report
+ generateReport(currentReport);
+
+ // Hide form, show report
+ document.querySelector('.form-section').style.display = 'none';
+ reportSection.style.display = 'block';
+
+ // Scroll to report
+ reportSection.scrollIntoView({ behavior: 'smooth' });
+});
+
+// Clear form handler
+clearFormBtn.addEventListener('click', function() {
+ if (confirm('Вы уверены, что хотите очистить форму?')) {
+ reportForm.reset();
+ document.getElementById('examDate').valueAsDate = new Date();
+ }
+});
+
+// Download PDF handler
+downloadBtn.addEventListener('click', function() {
+ // In a real application, this would generate a PDF
+ // For now, we'll create a simple HTML version
+ const reportHTML = generateReportHTML(currentReport);
+ const blob = new Blob([reportHTML], { type: 'text/html' });
+ const url = URL.createObjectURL(blob);
+ const a = document.createElement('a');
+ a.href = url;
+ a.download = `DOZ3_Report_${currentReport.patientId}_${new Date().getTime()}.html`;
+ document.body.appendChild(a);
+ a.click();
+ document.body.removeChild(a);
+ URL.revokeObjectURL(url);
+});
+
+// Print handler
+printBtn.addEventListener('click', function() {
+ window.print();
+});
+
+// New report handler
+newReportBtn.addEventListener('click', function() {
+ reportForm.reset();
+ document.getElementById('examDate').valueAsDate = new Date();
+ document.querySelector('.form-section').style.display = 'block';
+ reportSection.style.display = 'none';
+ currentReport = null;
+ window.scrollTo({ top: 0, behavior: 'smooth' });
+});
+
+// Helper function to get exam type label
+function getExamTypeLabel(examType) {
+ const labels = {
+ 'fluorography': 'Флюорография',
+ 'radiography': 'Рентгенография',
+ 'ct': 'Компьютерная томография',
+ 'mammography': 'Маммография'
+ };
+ return labels[examType] || examType;
+}
+
+// Generate report HTML
+function generateReport(data) {
+ const html = `
+ Отчет ДОЗ-3 - Регистрация дозы облучения
+
+
+ Номер отчета: DOZ3-${data.patientId}-${Date.now()}
+
+
+
+ Дата генерации: ${data.generatedDate}
+
+
+
+
+ Данные пациента
+
+
+ ФИО пациента: ${escapeHtml(data.patientName)}
+
+
+
+ Номер пациента: ${escapeHtml(data.patientId)}
+
+
+ Данные обследования
+
+
+ Дата обследования: ${formatDate(data.examDate)}
+
+
+
+ Тип обследования: ${escapeHtml(data.examTypeLabel)}
+
+
+
+ Область обследования: ${escapeHtml(data.bodyPart)}
+
+
+
+ Доза облучения: ${escapeHtml(data.dose)} мЗв
+
+
+ Медицинский персонал
+
+
+ Врач: ${escapeHtml(data.doctor)}
+
+
+ ${data.notes ? `
+ Примечания
+
+ ${escapeHtml(data.notes)}
+
+ ` : ''}
+
+
+
+
+ Этот отчет сгенерирован автоматически системой X-Ray DOZ3 Report Generator.
+
+ `;
+
+ reportContent.innerHTML = html;
+}
+
+// Generate standalone HTML for download
+function generateReportHTML(data) {
+ return `
+
+
+
+
+
+ Отчет ДОЗ-3 - ${escapeHtml(data.patientName)}
+
+
+
+ ${reportContent.innerHTML}
+
+
+ `.trim();
+}
+
+// Helper function to escape HTML
+function escapeHtml(text) {
+ const div = document.createElement('div');
+ div.textContent = text;
+ return div.innerHTML;
+}
+
+// Helper function to format date
+function formatDate(dateString) {
+ const date = new Date(dateString);
+ return date.toLocaleDateString('ru-RU', {
+ year: 'numeric',
+ month: 'long',
+ day: 'numeric'
+ });
+}
+
+// Save reports to localStorage
+function saveReportToHistory(report) {
+ let history = JSON.parse(localStorage.getItem('doz3Reports') || '[]');
+ history.unshift({
+ ...report,
+ id: Date.now()
+ });
+ // Keep only last 50 reports
+ history = history.slice(0, 50);
+ localStorage.setItem('doz3Reports', JSON.stringify(history));
+}
+
+// Initialize
+console.log('X-Ray DOZ3 Report Generator initialized');
diff --git a/styles.css b/styles.css
new file mode 100644
index 0000000..67311fe
--- /dev/null
+++ b/styles.css
@@ -0,0 +1,251 @@
+:root {
+ --primary-color: #2563eb;
+ --secondary-color: #64748b;
+ --success-color: #10b981;
+ --danger-color: #ef4444;
+ --light-bg: #f8fafc;
+ --white: #ffffff;
+ --text-dark: #1e293b;
+ --text-light: #64748b;
+ --border-color: #e2e8f0;
+ --shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
+ --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
+}
+
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+body {
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
+ line-height: 1.6;
+ color: var(--text-dark);
+ background-color: var(--light-bg);
+}
+
+.container {
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 20px;
+}
+
+header {
+ text-align: center;
+ margin-bottom: 40px;
+ padding: 40px 20px;
+ background: linear-gradient(135deg, var(--primary-color) 0%, #1d4ed8 100%);
+ color: var(--white);
+ border-radius: 12px;
+ box-shadow: var(--shadow-lg);
+}
+
+header h1 {
+ font-size: 2.5rem;
+ margin-bottom: 10px;
+}
+
+.subtitle {
+ font-size: 1.2rem;
+ opacity: 0.9;
+}
+
+main {
+ display: grid;
+ gap: 30px;
+}
+
+section {
+ background: var(--white);
+ padding: 30px;
+ border-radius: 12px;
+ box-shadow: var(--shadow);
+}
+
+h2 {
+ color: var(--text-dark);
+ margin-bottom: 20px;
+ font-size: 1.8rem;
+ border-bottom: 3px solid var(--primary-color);
+ padding-bottom: 10px;
+}
+
+.form-group {
+ margin-bottom: 20px;
+}
+
+.form-group label {
+ display: block;
+ margin-bottom: 8px;
+ font-weight: 600;
+ color: var(--text-dark);
+}
+
+.form-group input,
+.form-group select,
+.form-group textarea {
+ width: 100%;
+ padding: 12px;
+ border: 2px solid var(--border-color);
+ border-radius: 8px;
+ font-size: 1rem;
+ transition: border-color 0.3s ease;
+}
+
+.form-group input:focus,
+.form-group select:focus,
+.form-group textarea:focus {
+ outline: none;
+ border-color: var(--primary-color);
+}
+
+.form-group textarea {
+ resize: vertical;
+ font-family: inherit;
+}
+
+.btn {
+ padding: 12px 24px;
+ border: none;
+ border-radius: 8px;
+ font-size: 1rem;
+ font-weight: 600;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ margin-right: 10px;
+ margin-bottom: 10px;
+}
+
+.btn-primary {
+ background-color: var(--primary-color);
+ color: var(--white);
+}
+
+.btn-primary:hover {
+ background-color: #1d4ed8;
+ transform: translateY(-2px);
+ box-shadow: var(--shadow-lg);
+}
+
+.btn-secondary {
+ background-color: var(--secondary-color);
+ color: var(--white);
+}
+
+.btn-secondary:hover {
+ background-color: #475569;
+ transform: translateY(-2px);
+ box-shadow: var(--shadow-lg);
+}
+
+.btn-link {
+ background-color: transparent;
+ color: var(--primary-color);
+ border: 2px solid var(--primary-color);
+ text-decoration: none;
+ display: inline-block;
+}
+
+.btn-link:hover {
+ background-color: var(--primary-color);
+ color: var(--white);
+}
+
+.report-content {
+ background-color: var(--light-bg);
+ padding: 30px;
+ border-radius: 8px;
+ margin-bottom: 20px;
+ border-left: 4px solid var(--primary-color);
+}
+
+.report-content h3 {
+ color: var(--primary-color);
+ margin-bottom: 15px;
+}
+
+.report-content .report-field {
+ margin-bottom: 15px;
+ padding: 10px;
+ background-color: var(--white);
+ border-radius: 6px;
+}
+
+.report-content .report-field strong {
+ color: var(--text-dark);
+ display: inline-block;
+ min-width: 200px;
+}
+
+.report-actions {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 10px;
+}
+
+.info-section ul {
+ margin-left: 20px;
+ margin-top: 15px;
+}
+
+.info-section li {
+ margin-bottom: 8px;
+ color: var(--text-light);
+}
+
+.info-section p {
+ color: var(--text-light);
+ margin-bottom: 15px;
+}
+
+.documentation {
+ margin-top: 25px;
+ padding-top: 20px;
+ border-top: 1px solid var(--border-color);
+}
+
+footer {
+ text-align: center;
+ margin-top: 40px;
+ padding: 20px;
+ color: var(--text-light);
+}
+
+@media print {
+ body {
+ background-color: var(--white);
+ }
+
+ .form-section,
+ .info-section,
+ .report-actions,
+ header,
+ footer {
+ display: none !important;
+ }
+
+ .report-section {
+ display: block !important;
+ box-shadow: none;
+ }
+}
+
+@media (max-width: 768px) {
+ header h1 {
+ font-size: 2rem;
+ }
+
+ .subtitle {
+ font-size: 1rem;
+ }
+
+ section {
+ padding: 20px;
+ }
+
+ .btn {
+ width: 100%;
+ margin-right: 0;
+ }
+}
From 29436b19fe8f55284c2c074099be810a8d3d4a02 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 29 Dec 2025 22:18:54 +0000
Subject: [PATCH 3/5] Fix: Update button text and comments to accurately
reflect HTML download functionality
Co-authored-by: GraphSaf <63410676+GraphSaf@users.noreply.github.com>
---
index.html | 2 +-
script.js | 5 ++---
2 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/index.html b/index.html
index 219e7ce..4840f58 100644
--- a/index.html
+++ b/index.html
@@ -73,7 +73,7 @@ Создание отчета
Сгенерированный отчет
-
+
diff --git a/script.js b/script.js
index 31f65ee..2efd5f0 100644
--- a/script.js
+++ b/script.js
@@ -51,10 +51,9 @@ clearFormBtn.addEventListener('click', function() {
}
});
-// Download PDF handler
+// Download report handler
downloadBtn.addEventListener('click', function() {
- // In a real application, this would generate a PDF
- // For now, we'll create a simple HTML version
+ // Generate and download the report as an HTML file
const reportHTML = generateReportHTML(currentReport);
const blob = new Blob([reportHTML], { type: 'text/html' });
const url = URL.createObjectURL(blob);
From 705d3f4367381109a4131e51fb52b53e3234ccaf Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 29 Dec 2025 22:20:42 +0000
Subject: [PATCH 4/5] Refactor: Fix circular dependency and remove dead code
Co-authored-by: GraphSaf <63410676+GraphSaf@users.noreply.github.com>
---
script.js | 96 +++++++++++++++++++++++++------------------------------
1 file changed, 44 insertions(+), 52 deletions(-)
diff --git a/script.js b/script.js
index 2efd5f0..b4fa74e 100644
--- a/script.js
+++ b/script.js
@@ -94,7 +94,50 @@ function getExamTypeLabel(examType) {
// Generate report HTML
function generateReport(data) {
- const html = `
+ reportContent.innerHTML = generateReportContent(data);
+}
+
+// Generate standalone HTML for download
+function generateReportHTML(data) {
+ const reportHTML = generateReportContent(data);
+ return `
+
+
+
+
+
+ Отчет ДОЗ-3 - ${escapeHtml(data.patientName)}
+
+
+
+ ${reportHTML}
+
+
+ `.trim();
+}
+
+// Helper to generate report content HTML
+function generateReportContent(data) {
+ return `
Отчет ДОЗ-3 - Регистрация дозы облучения
@@ -154,45 +197,6 @@ function generateReport(data) {
Этот отчет сгенерирован автоматически системой X-Ray DOZ3 Report Generator.
`;
-
- reportContent.innerHTML = html;
-}
-
-// Generate standalone HTML for download
-function generateReportHTML(data) {
- return `
-
-
-
-
-
-
Отчет ДОЗ-3 - ${escapeHtml(data.patientName)}
-
-
-
- ${reportContent.innerHTML}
-
-
- `.trim();
}
// Helper function to escape HTML
@@ -212,17 +216,5 @@ function formatDate(dateString) {
});
}
-// Save reports to localStorage
-function saveReportToHistory(report) {
- let history = JSON.parse(localStorage.getItem('doz3Reports') || '[]');
- history.unshift({
- ...report,
- id: Date.now()
- });
- // Keep only last 50 reports
- history = history.slice(0, 50);
- localStorage.setItem('doz3Reports', JSON.stringify(history));
-}
-
// Initialize
console.log('X-Ray DOZ3 Report Generator initialized');
From e9e0a06feffd4726b41909e401909735a3428c08 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 29 Dec 2025 22:21:58 +0000
Subject: [PATCH 5/5] Add date validation in formatDate function
Co-authored-by: GraphSaf <63410676+GraphSaf@users.noreply.github.com>
---
script.js | 3 +++
1 file changed, 3 insertions(+)
diff --git a/script.js b/script.js
index b4fa74e..c2b5e27 100644
--- a/script.js
+++ b/script.js
@@ -209,6 +209,9 @@ function escapeHtml(text) {
// Helper function to format date
function formatDate(dateString) {
const date = new Date(dateString);
+ if (isNaN(date.getTime())) {
+ return dateString; // Return original string if invalid
+ }
return date.toLocaleDateString('ru-RU', {
year: 'numeric',
month: 'long',