import express from "express";
import axios from "axios";
import cors from "cors";
import mysql from "mysql2";
import dotenv from "dotenv";
// Загружаем переменные окружения из файла .env
dotenv.config();
const app = express();
const PORT = 3000;
app.use(cors());
app.use(express.json());
// ✅ Подключение к базе данных MySQL
const db = mysql.createConnection({
host: process.env.DB_HOST,`your text`
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
});
// Проверка подключения
db.connect((err) => {
if (err) {
console.error("❌ Ошибка подключения к базе данных:", err);
return;
}
console.log("✅ Подключено к базе данных MySQL");
});
// ✅ Настройки Яндекс Саджест
const API_KEY = process.env.API_KEY;
const SUGGEST_URL = "https://suggest-maps.yandex.ru/v1/suggest";
// Функция получения подсказок
const fetchSuggestions = async (query, types) => {
try {
const url = `${SUGGEST_URL}?apikey=${API_KEY}&text=${encodeURIComponent(query)}&lang=ru_RU&types=${types}`;
console.log("? Запрос к Яндекс Саджесту:", url);
const response = await axios.get(url, {
headers: {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
},
});
if (response.status !== 200) {
console.error(`❌ Ошибка API: ${response.status} ${response.statusText}`, response.data);
return [];
}
const data = response.data;
if (!data.results) {
console.warn("⚠️ Пустой ответ от API:", data);
return [];
}
// Уникальные подсказки по тексту
return [...new Set(data.results.map((item) => item.title.text))];
} catch (error) {
console.error("❌ Ошибка при запросе к API:", error.response?.status, error.response?.data || error.message);
return [];
}
};
// ✅ Маршрут получения подсказок
app.get("/suggest", async (req, res) => {
const { query, type, city, street } = req.query;
if (!query) {
return res.status(400).json({ error: "Запрос пуст" });
}
let types;
let fullQuery = query;
switch (type) {
case "city":
types = "geo";
break;
case "street":
if (!city) return res.status(400).json({ error: "Город обязателен для поиска улиц" });
types = "street";
fullQuery = `${city} ${query}`;
break;
case "house":
if (!city || !street) return res.status(400).json({ error: "Город и улица обязательны для поиска домов" });
types = "house";
fullQuery = `${city} ${street} ${query}`;
break;
default:
return res.status(400).json({ error: "Некорректный тип поиска" });
}
const suggestions = await fetchSuggestions(fullQuery, types);
res.json({ suggestions });
});
// ✅ Логин пользователя
app.post("/api/login", (req, res) => {
const { loginType, city, street, house, apartment, contract } = req.body;
let query;
let values;
if (loginType === "address") {
query = `
SELECT user_id, is_special_user FROM users
WHERE city = ? AND street = ? AND house = ? AND apartment = ? AND contract_number = ?
`;
values = [city, street, house, apartment, contract];
} else if (loginType === "account") {
query = `
SELECT user_id, is_special_user FROM users
WHERE contract_number = ?
`;
values = [contract];
} else {
return res.status(400).json({ error: "Некорректный тип логина" });
}
db.query(query, values, (err, results) => {
if (err) {
console.error("❌ Ошибка при запросе к базе:", err);
return res.status(500).json({ error: "Ошибка сервера при логине" });
}
if (results.length > 0) {
const user = results[0];
console.log("✅ Данные из БД:", user);
console.log("? is_special_user значение:", user.is_special_user);
console.log("? typeof is_special_user:", typeof user.is_special_user);
res.json({
success: true,
userId: user.user_id,
isSpecialUser: Boolean(Number(user.is_special_user)), // ? Гарантированное приведение типа
});
} else {
res.status(401).json({ success: false, error: "Пользователь не найден" });
}
});
});
// ✅ Получение всех новостей
app.get("/api/news", (req, res) => {
db.query("SELECT * FROM news ORDER BY created_at DESC", (err, results) => {
if (err) {
console.error("❌ Ошибка загрузки новостей:", err);
return res.status(500).json({ error: "Ошибка сервера" });
}
res.json(results);
});
});
// ✅ Добавление новости (только для specialUser)
app.post("/api/news", (req, res) => {
const { title, content, userId } = req.body;
console.log("? Полученные данные:", req.body); // ЛОГИРОВАНИЕ ДАННЫХ
if (!title || !content || !userId) {
return res.status(400).json({ error: "Заголовок, текст и userId обязательны" });
}
const checkUserQuery = "SELECT is_special_user FROM users WHERE user_id = ?";
db.query(checkUserQuery, [userId], (err, results) => {
if (err) {
console.error("❌ Ошибка при проверке пользователя:", err);
return res.status(500).json({ error: "Ошибка сервера" });
}
console.log("? Результат проверки пользователя:", results); // ЛОГИРУЕМ SQL-ОТВЕТ
if (results.length === 0 || !results[0].is_special_user) {
return res.status(403).json({ error: "Нет прав на добавление новостей" });
}
const insertQuery = "INSERT INTO news (title, content) VALUES (?, ?)";
db.query(insertQuery, [title, content], (err) => {
if (err) {
console.error("❌ Ошибка при добавлении новости:", err);
return res.status(500).json({ error: "Ошибка сервера" });
}
console.log("✅ Новость добавлена!");
res.json({ success: true, message: "Новость добавлена" });
});
});
});
// Маршрут для удаления новости
app.delete("/api/news/:id", (req, res) => {
const { id } = req.params; // Получаем ID новости из параметров URL
const { userId } = req.query; // Получаем userId из query-параметра
if (!userId) {
return res.status(400).json({ error: "Не указан userId" });
}
// Проверка, является ли пользователь особым (specialUser)
const checkUserQuery = "SELECT is_special_user FROM users WHERE user_id = ?";
db.query(checkUserQuery, [userId], (err, results) => {
if (err) {
console.error("❌ Ошибка при проверке пользователя:", err);
return res.status(500).json({ error: "Ошибка сервера" });
}
if (results.length === 0 || !results[0].is_special_user) {
return res.status(403).json({ error: "Нет прав на удаление новостей" });
}
// Удаление новости из базы данных
const deleteQuery = "DELETE FROM news WHERE id = ?";
db.query(deleteQuery, [id], (err) => {
if (err) {
console.error("❌ Ошибка при удалении новости:", err);
return res.status(500).json({ error: "Ошибка при удалении новости" });
}
res.json({ success: true, message: "Новость удалена" });
});
});
});
// ✅ Получение последних показаний
app.get("/api/meter-readings", (req, res) => {
console.log("? Запрос получен:", req.query); // Лог запроса
const { userId } = req.query;
if (!userId) {
return res.status(400).json({ error: "Не указан userId" });
}
const query = `
SELECT hot_water, cold_water, electricity, reading_date
FROM meter_readings
WHERE user_id = ?
ORDER BY reading_date DESC
LIMIT 1
`;
db.query(query, [userId], (err, results) => {
if (err) {
console.error("❌ Ошибка при получении показаний:", err);
return res.status(500).json({ error: "Ошибка сервера" });
}
const readings = results[0] || {
hot_water: 0,
cold_water: 0,
electricity: 0,
reading_date: null,
};
console.log("✅ Последние показания:", readings);
res.setHeader("Content-Type", "application/json"); // Указываем JSON-ответ
res.json({ readings });
});
});
// ✅ Добавление или обновление показаний
app.post("/api/meter-readings", (req, res) => {
const { userId, hotWater, coldWater, electricity, readingDate } = req.body;
if (!userId || !readingDate) {
return res.status(400).json({ error: "Не указан userId или дата показаний" });
}
const checkExistingQuery = `
SELECT id FROM meter_readings
WHERE user_id = ?
ORDER BY reading_date DESC
LIMIT 1
`;
db.query(checkExistingQuery, [userId], (err, results) => {
if (err) {
console.error("❌ Ошибка при проверке существующих показаний:", err);
return res.status(500).json({ error: "Ошибка при проверке существующих показаний" });
}
if (results.length > 0) {
// Если запись существует, обновляем её
const readingId = results[0].id;
const updateQuery = `
UPDATE meter_readings
SET hot_water = ?, cold_water = ?, electricity = ?, reading_date = ?
WHERE id = ?
`;
const updateValues = [hotWater, coldWater, electricity, readingDate, readingId];
db.query(updateQuery, updateValues, (err) => {
if (err) {
console.error("❌ Ошибка при обновлении показаний:", err);
return res.status(500).json({ error: "Ошибка при обновлении показаний" });
}
console.log("✅ Показания успешно обновлены");
res.json({ success: true });
});
} else {
// Если записи нет, добавляем новую
const insertQuery = `
INSERT INTO meter_readings (user_id, hot_water, cold_water, electricity, reading_date)
VALUES (?, ?, ?, ?, ?)
`;
const insertValues = [userId, hotWater, coldWater, electricity, readingDate];
db.query(insertQuery, insertValues, (err) => {
if (err) {
console.error("❌ Ошибка при добавлении показаний:", err);
return res.status(500).json({ error: "Ошибка при добавлении показаний" });
}
console.log("✅ Показания успешно добавлены");
res.json({ success: true });
});
}
});
});
// ✅ Расчет оплаты по показаниям
const tariffs = {
heating: 500,
maintenance: 300,
hot_water: 17.51,
cold_water: 80.69,
electricity: 4.70,
};
app.get("/api/calculate-payment", async (req, res) => {
const { userId, selectedServices } = req.query;
if (!userId || !selectedServices) {
return res.status(400).json({ error: "Не указан userId или выбранные услуги" });
}
const selectedServicesArray = selectedServices.split(",").map((s) => s.trim()).filter(Boolean);
let totalAmount = 0;
// Фиксированные тарифы
if (selectedServicesArray.includes("heating")) totalAmount += tariffs.heating;
if (selectedServicesArray.includes("maintenance")) totalAmount += tariffs.maintenance;
// Динамические услуги (электричество, вода)
const query = `
SELECT hot_water, cold_water, electricity, reading_date
FROM meter_readings
WHERE user_id = ?
ORDER BY reading_date DESC
LIMIT 2
`;
db.query(query, [userId], (err, results) => {
if (err) {
console.error("❌ Ошибка при получении данных о показаниях:", err);
return res.status(500).json({ error: "Ошибка при получении показаний" });
}
if (results.length === 0) {
return res.json({ totalAmount: totalAmount.toFixed(2), warning: "Нет данных о предыдущих показаниях" });
}
const current = results[0];
const previous = results[1] || { hot_water: 0, cold_water: 0, electricity: 0 };
const consumption = {
hot_water: Math.max(current.hot_water - previous.hot_water, 0),
cold_water: Math.max(current.cold_water - previous.cold_water, 0),
electricity: Math.max(current.electricity - previous.electricity, 0),
};
console.log("? Разница в показаниях:", consumption);
if (selectedServicesArray.includes("hot_water")) totalAmount += consumption.hot_water * tariffs.hot_water;
if (selectedServicesArray.includes("cold_water")) totalAmount += consumption.cold_water * tariffs.cold_water;
if (selectedServicesArray.includes("electricity")) totalAmount += consumption.electricity * tariffs.electricity;
res.json({
totalAmount: totalAmount.toFixed(2),
details: {
heating: selectedServicesArray.includes("heating") ? tariffs.heating : 0,
maintenance: selectedServicesArray.includes("maintenance") ? tariffs.maintenance : 0,
hot_water: consumption.hot_water * tariffs.hot_water,
cold_water: consumption.cold_water * tariffs.cold_water,
electricity: consumption.electricity * tariffs.electricity,
},
});
});
});
// ✅ Запуск сервера
app.listen(PORT, () => {
console.log(`? Сервер запущен на http://localhost:${PORT}`);
});
Должен быть json как в meters, но почему то возвращает html