Initial commit.
This commit is contained in:
commit
ef812f7fd9
3 changed files with 280 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
.idea
|
||||
BIN
favicon.png
Normal file
BIN
favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.7 KiB |
279
index.html
Normal file
279
index.html
Normal file
|
|
@ -0,0 +1,279 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Проверка наличия льготных препаратов</title>
|
||||
<link rel="icon" type="image/png" href="/favicon.png">
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 20px;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
.container {
|
||||
max-width: 700px;
|
||||
margin: 0 auto;
|
||||
background-color: white;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
}
|
||||
h2 {
|
||||
color: #333;
|
||||
text-align: center;
|
||||
}
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 20px;
|
||||
}
|
||||
th, td {
|
||||
border: 1px solid #ddd;
|
||||
padding: 12px;
|
||||
text-align: left;
|
||||
}
|
||||
th {
|
||||
background-color: #195695;
|
||||
color: white;
|
||||
}
|
||||
u {
|
||||
border-bottom: 1px dashed #cccccc;
|
||||
text-decoration: none;
|
||||
cursor: help;
|
||||
}
|
||||
.name {
|
||||
background-color: #e6f2ff;
|
||||
text-align: center;
|
||||
color: #195695;
|
||||
}
|
||||
.loading {
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
font-style: italic;
|
||||
color: #666;
|
||||
}
|
||||
.error {
|
||||
color: red;
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
}
|
||||
.note {
|
||||
margin-top: 10px;
|
||||
font-size: small;
|
||||
text-align: center;
|
||||
}
|
||||
.search-container {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
justify-content: center;
|
||||
}
|
||||
#searchInput {
|
||||
flex: 1;
|
||||
min-width: 220px;
|
||||
max-width: 280px;
|
||||
padding: 10px;
|
||||
font-size: 16px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
}
|
||||
#searchButton {
|
||||
padding: 10px 20px;
|
||||
font-size: 16px;
|
||||
background-color: #6d4203;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
#searchButton:hover {
|
||||
background-color: #8f6f3f;
|
||||
}
|
||||
|
||||
/* Responsive behavior for smaller screens */
|
||||
@media (max-width: 600px) {
|
||||
.search-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
#searchInput {
|
||||
align-self: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
#searchButton {
|
||||
align-self: center;
|
||||
width: 90%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (hover: none) {
|
||||
u {
|
||||
border-bottom: none !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h2>Проверка наличия льготных препаратов<br/>в аптеках Санкт-Петербурга</h2>
|
||||
|
||||
<div class="search-container">
|
||||
<input type="text" id="searchInput" placeholder="Введите название препарата">
|
||||
<button id="searchButton">Найти</button>
|
||||
</div>
|
||||
|
||||
<div id="content"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function fetchData(name) {
|
||||
document.getElementById('content').innerHTML = '<div class="loading">Загрузка данных...</div>';
|
||||
name = name.replaceAll(' ', '_');
|
||||
fetch(`/api-proxy?operation=getMedicament&filter=${name}`)
|
||||
.then(response => response.json())
|
||||
.then(data => displayData(processData(data)))
|
||||
.catch(error => showError(error));
|
||||
}
|
||||
|
||||
// Extract needed data from JSON
|
||||
function processData(data) {
|
||||
if (data['status'] !== "SUCCESS")
|
||||
return data['errors'];
|
||||
|
||||
const results = data['model']['result'];
|
||||
let processedData = [];
|
||||
|
||||
results.forEach(result => {
|
||||
result['districts'].forEach(district => {
|
||||
district['apothecaries'].forEach(apothecary => {
|
||||
let address = apothecary['address'];
|
||||
const regex = /\d*, [а-яА-Я\-. ]+, (.+) \*.+/;
|
||||
let m;
|
||||
if ((m = regex.exec(address)) !== null)
|
||||
address = m[1];
|
||||
else
|
||||
address = address.substring(0, address.indexOf('*'));
|
||||
|
||||
processedData.push({
|
||||
name: result['name'],
|
||||
apothecary: apothecary['name'] + '<br/><i>' + address + '</i>',
|
||||
countFederal: apothecary['ost1'],
|
||||
countRegional: apothecary['ost2'],
|
||||
timestamp: apothecary['date']
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return processedData;
|
||||
}
|
||||
|
||||
// Display the data in a table format
|
||||
function displayData(data) {
|
||||
let htmlContent;
|
||||
|
||||
if (typeof(data) === 'object') {
|
||||
htmlContent = `
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Аптека</th>
|
||||
<th style="width: 75px; text-align: center;">Остаток<br/>(<u title="региональная льгота">рег</u>/<u title="федеральная льгота">фед</u>)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
`;
|
||||
|
||||
// Group consecutive items with same name and generate merged cells
|
||||
if (data.length > 0) {
|
||||
let currentName = data[0].name;
|
||||
let rowCount = 1;
|
||||
let rowStartIndex = 0;
|
||||
|
||||
for (let i = 1; i <= data.length; i++) {
|
||||
if (i < data.length && data[i].name === currentName) {
|
||||
rowCount++;
|
||||
} else {
|
||||
// Generate rows for the current group
|
||||
htmlContent += '<tr><td colspan="2"></td></tr>';
|
||||
htmlContent += `<tr><td colspan="2" class="name"><b>${currentName}</b></td></tr>`;
|
||||
for (let j = rowStartIndex; j < i; j++) {
|
||||
const item = data[j];
|
||||
htmlContent += `
|
||||
<tr>
|
||||
<td>${item.apothecary}</td>
|
||||
<td style="text-align: center;">${item.countRegional} / ${item.countFederal}</td>
|
||||
</tr>`;
|
||||
}
|
||||
|
||||
// Reset for next group
|
||||
if (i < data.length) {
|
||||
currentName = data[i].name;
|
||||
rowCount = 1;
|
||||
rowStartIndex = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
htmlContent += `
|
||||
</tbody>
|
||||
</table>
|
||||
`;
|
||||
|
||||
htmlContent += '<div class="note">Информация получена через <a href="https://eservice.gu.spb.ru/portalFront/resources/portal.html#medicament" target="_blank" style="text-decoration: none;">портал госуслуг Санкт-Петербурга</a>.</div>'
|
||||
}
|
||||
else
|
||||
htmlContent = `<div class="error">${data}</div>`;
|
||||
|
||||
document.getElementById('content').innerHTML = htmlContent;
|
||||
}
|
||||
|
||||
function showError(error) {
|
||||
document.getElementById('content').innerHTML = `<div class="error">Ошибка: ${error.message}</div>`;
|
||||
}
|
||||
|
||||
function search() {
|
||||
const name = document.getElementById('searchInput').value.trim();
|
||||
if (name) {
|
||||
saveInputValue();
|
||||
fetchData(name);
|
||||
}
|
||||
}
|
||||
|
||||
// Save input value to localStorage
|
||||
function saveInputValue() {
|
||||
const name = document.getElementById('searchInput').value;
|
||||
localStorage.setItem('medicamentName', name);
|
||||
}
|
||||
|
||||
// Restore input value from localStorage
|
||||
function restoreInputValue() {
|
||||
const savedValue = localStorage.getItem('medicamentName');
|
||||
if (savedValue) {
|
||||
document.getElementById('searchInput').value = savedValue;
|
||||
return savedValue;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
let name = restoreInputValue();
|
||||
if (name !== null)
|
||||
fetchData(name);
|
||||
});
|
||||
|
||||
document.getElementById('searchButton').addEventListener('click', search);
|
||||
document.getElementById('searchInput').addEventListener('keypress', (e) => {
|
||||
if (e.key === 'Enter')
|
||||
search();
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Add table
Reference in a new issue