This commit is contained in:
2026-01-18 00:08:03 +04:00
parent 46cd4ef38c
commit 3ec042d542
14 changed files with 48 additions and 68 deletions

5
.vscode/extensions.json vendored Normal file
View File

@@ -0,0 +1,5 @@
{
"recommendations": [
"ms-dotnettools.csharp"
]
}

2
.vscode/launch.json vendored
View File

@@ -5,7 +5,7 @@
{
"name": "Debug React App",
"type": "firefox",
"type": "chrome",
"request": "launch",
"url": "http://localhost:3000",
"webRoot": "${workspaceFolder}/src",

30
db.json
View File

@@ -5,7 +5,7 @@
"clientName": "Иванов Иван Иванович",
"orderCost": 15000,
"orderDate": "2025-01-15",
"status": "in_progress",
"status": "completed",
"address": "ул. Ленина, 10",
"description": "Доставка строительных материалов"
},
@@ -32,7 +32,7 @@
"clientName": "Сергеев Алексей Петрович",
"orderCost": 12000,
"orderDate": "2025-01-18",
"status": "pending",
"status": "in_progress",
"address": "пр. Космонавтов, 78",
"description": "Переезд квартиры"
},
@@ -77,7 +77,7 @@
"clientName": "Александрова Ольга Викторовна",
"orderCost": 9500,
"orderDate": "2025-01-23",
"status": "pending",
"status": "cancelled",
"address": "ул. Центральная, 89",
"description": "Перевозка личных вещей"
},
@@ -184,14 +184,6 @@
"endTime": "12:00",
"date": "2025-11-21"
},
{
"id": "e320",
"vehicleId": "1",
"orderId": "1",
"startTime": "08:00",
"endTime": "10:00",
"date": "2025-11-21"
},
{
"id": "08a1",
"vehicleId": "2",
@@ -207,6 +199,22 @@
"startTime": "08:00",
"endTime": "09:00",
"date": "2025-11-21"
},
{
"id": "6f66",
"vehicleId": "1",
"orderId": "1",
"startTime": "08:00",
"endTime": "11:00",
"date": "2025-11-21"
},
{
"id": "f275",
"vehicleId": "2",
"orderId": "4",
"startTime": "08:00",
"endTime": "10:00",
"date": "2025-11-23"
}
]
}

View File

@@ -1,4 +1,4 @@
import React from 'react';
import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom';
import OrdersPage from './pages/OrdersPage';
import VehiclesPage from './pages/VehiclesPage';
@@ -6,43 +6,29 @@ import VehicleDetailPage from './pages/VehicleDetailPage';
import 'bootstrap/dist/css/bootstrap.min.css';
import './App.css';
const App: React.FC = () => {
const App = () => {
return (
<Router>
<div className="App">
{/* Навигация */}
<nav className="navbar navbar-expand-lg navbar-dark bg-primary">
<nav className="navbar navbar-dark bg-primary">
<div className="container">
<Link className="navbar-brand" to="/">
Логистическая компания
</Link>
<button
className="navbar-toggler"
type="button"
data-bs-toggle="collapse"
data-bs-target="#navbarNav"
>
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbarNav">
<ul className="navbar-nav">
<li className="nav-item">
<Link className="nav-link" to="/orders">
<div className="d-flex">
<Link className="nav-link text-white me-3" to="/orders">
Заказы
</Link>
</li>
<li className="nav-item">
<Link className="nav-link" to="/vehicles">
<Link className="nav-link text-white" to="/vehicles">
Машины
</Link>
</li>
</ul>
</div>
</div>
</nav>
{/* Основной контент */}
<main>
<main className="container mt-4">
<Routes>
<Route path="/" element={<OrdersPage />} />
<Route path="/orders" element={<OrdersPage />} />

View File

@@ -9,8 +9,6 @@ interface WaybillWidgetProps {
date: string;
}
let durationOrder;
const WaybillWidget: React.FC<WaybillWidgetProps> = ({ vehicleId, date }) => {
const [entries, setEntries] = useState<WaybillEntry[]>([]);
const [orders, setOrders] = useState<Order[]>([]);
@@ -21,7 +19,7 @@ const WaybillWidget: React.FC<WaybillWidgetProps> = ({ vehicleId, date }) => {
const [selectedTimeSlot, setSelectedTimeSlot] = useState<string | null>(null);
const [duration, setDuration] = useState<number>(2);
// Часовые интервалы с 8:00 до 20:00
const timeSlots = Array.from({ length: 13 }, (_, i) => {
const hour = i + 8;
return `${hour.toString().padStart(2, '0')}:00`;
@@ -34,14 +32,14 @@ const WaybillWidget: React.FC<WaybillWidgetProps> = ({ vehicleId, date }) => {
setLoading(true);
setError(null);
// Загружаем записи путевого листа
const entriesResponse = await waybillApi.getEntries();
const vehicleEntries = entriesResponse.data.filter(
entry => entry.vehicleId === vehicleId && entry.date === date
);
setEntries(vehicleEntries);
// Загружаем доступные заказы
const ordersResponse = await ordersApi.getOrders();
const assignedOrderIds = new Set(vehicleEntries.map(entry => entry.orderId));
const available = ordersResponse.data.filter(
@@ -71,13 +69,12 @@ const WaybillWidget: React.FC<WaybillWidgetProps> = ({ vehicleId, date }) => {
};
const getOrderInfo = (orderId: number, allOrders: Order[]): Order | undefined => {
// Ищем заказ среди всех заказов
const foundOrder = allOrders.find(order => order.id === orderId);
if (foundOrder) {
return foundOrder;
}
// Если заказ не найден, но есть в путевом листе - создаем базовый объект
const waybillEntry = entries.find(entry => entry.orderId === orderId);
if (waybillEntry) {
const basicOrder: Order = {
@@ -92,7 +89,6 @@ const WaybillWidget: React.FC<WaybillWidgetProps> = ({ vehicleId, date }) => {
return basicOrder;
}
// Если заказ не найден нигде
return undefined;
};
@@ -100,7 +96,7 @@ const WaybillWidget: React.FC<WaybillWidgetProps> = ({ vehicleId, date }) => {
if (selectedOrder) {
try {
const startHour = parseInt(timeSlot.split(':')[0]);
const endHour = startHour + duration; // Используем выбранную длительность
const endHour = startHour + duration;
const newEntry: Omit<WaybillEntry, 'id'> = {
vehicleId,
@@ -128,7 +124,7 @@ const WaybillWidget: React.FC<WaybillWidgetProps> = ({ vehicleId, date }) => {
if (selectedTimeSlot) {
try {
const startHour = parseInt(selectedTimeSlot.split(':')[0]);
const endHour = startHour + duration; // Используем выбранную длительность
const endHour = startHour + duration;
const newEntry: Omit<WaybillEntry, 'id'> = {
vehicleId,
@@ -172,7 +168,6 @@ const WaybillWidget: React.FC<WaybillWidgetProps> = ({ vehicleId, date }) => {
<h5 className="mb-0">Путевой лист на {new Date(date).toLocaleDateString()}</h5>
</div>
<div className="card-body">
{/* Состояние выбора */}
<div className="alert alert-info mb-3">
{selectedOrder && !selectedTimeSlot && (
<div>
@@ -220,7 +215,6 @@ const WaybillWidget: React.FC<WaybillWidgetProps> = ({ vehicleId, date }) => {
</p>
)}
</div>
{/* Таблица временных интервалов */}
<div className="table-responsive mb-4">
<table className="table table-bordered">
<thead>
@@ -275,7 +269,6 @@ const WaybillWidget: React.FC<WaybillWidgetProps> = ({ vehicleId, date }) => {
</table>
</div>
{/* Список доступных заказов */}
<div className="available-orders">
<h6>Доступные заказы:</h6>
<div className="row">

View File

@@ -19,7 +19,6 @@ const OrdersPage: React.FC = () => {
status: ''
});
// Загрузка данных
const loadOrders = async () => {
try {
setLoading(true);
@@ -35,23 +34,18 @@ const OrdersPage: React.FC = () => {
}
};
// Функция изменения статуса заказа
const updateOrderStatus = async (orderId: number, newStatus: Order['status']) => {
try {
// Находим заказ для обновления
const orderToUpdate = orders.find(order => order.id === orderId);
if (!orderToUpdate) return;
// Создаем обновленный заказ
const updatedOrder = {
...orderToUpdate,
status: newStatus
};
// Отправляем запрос на сервер
await ordersApi.updateOrder(orderId, updatedOrder);
// Обновляем локальное состояние
setOrders(prevOrders =>
prevOrders.map(order =>
order.id === orderId ? updatedOrder : order
@@ -69,7 +63,6 @@ const OrdersPage: React.FC = () => {
loadOrders();
}, []);
// Применение фильтров
useEffect(() => {
let result = orders;

View File

@@ -23,11 +23,9 @@ const VehicleDetailPage: React.FC = () => {
setLoading(true);
setError(null);
// Загружаем данные машины
const vehicleResponse = await vehiclesApi.getVehicle(parseInt(id));
setVehicle(vehicleResponse.data);
// Загружаем историю выполненных заказов
const ordersResponse = await ordersApi.getOrders();
const completed = ordersResponse.data.filter(
order => order.status === 'completed'

View File

@@ -1,27 +1,24 @@
import axios from 'axios';
import { Order, Vehicle, WaybillEntry } from '../types';
const API_BASE = 'http://localhost:3001';
const API_BASE = 'http://localhost:3001/';
const api = axios.create({
baseURL: API_BASE,
});
// Сервис для работы с заказами
// Сервис для работы с заказами
export const ordersApi = {
getOrders: () => api.get<Order[]>('/orders'),
getOrder: (id: number) => api.get<Order>(`/orders/${id}`),
updateOrder: (id: number, order: Order) => api.put<Order>(`/orders/${id}`, order),
};
// Сервис для работы с машинами
export const vehiclesApi = {
getVehicles: () => api.get<Vehicle[]>('/vehicles'),
getVehicle: (id: number) => api.get<Vehicle>(`/vehicles/${id}`),
};
// Сервис для работы с путевыми листами
export const waybillApi = {
getEntries: () => api.get<WaybillEntry[]>('/waybillEntries'),
createEntry: (entry: Omit<WaybillEntry, 'id'>) =>

View File

@@ -1,4 +1,4 @@
// Основные типы данных
export interface Order {
id: number;
clientName: string;