update
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
5
.vscode/extensions.json
vendored
Normal file
5
.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"ms-dotnettools.csharp"
|
||||
]
|
||||
}
|
||||
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
@@ -5,7 +5,7 @@
|
||||
|
||||
{
|
||||
"name": "Debug React App",
|
||||
"type": "firefox",
|
||||
"type": "chrome",
|
||||
"request": "launch",
|
||||
"url": "http://localhost:3000",
|
||||
"webRoot": "${workspaceFolder}/src",
|
||||
|
||||
30
db.json
30
db.json
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
40
src/App.tsx
40
src/App.tsx
@@ -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">
|
||||
Заказы
|
||||
</Link>
|
||||
</li>
|
||||
<li className="nav-item">
|
||||
<Link className="nav-link" to="/vehicles">
|
||||
Машины
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
<div className="d-flex">
|
||||
<Link className="nav-link text-white me-3" to="/orders">
|
||||
Заказы
|
||||
</Link>
|
||||
<Link className="nav-link text-white" to="/vehicles">
|
||||
Машины
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
{/* Основной контент */}
|
||||
<main>
|
||||
<main className="container mt-4">
|
||||
<Routes>
|
||||
<Route path="/" element={<OrdersPage />} />
|
||||
<Route path="/orders" element={<OrdersPage />} />
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -22,12 +22,10 @@ const VehicleDetailPage: React.FC = () => {
|
||||
try {
|
||||
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'
|
||||
|
||||
@@ -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'>) =>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Основные типы данных
|
||||
|
||||
export interface Order {
|
||||
id: number;
|
||||
clientName: string;
|
||||
|
||||
Reference in New Issue
Block a user