добавляю скрипты по части фронта
This commit is contained in:
@@ -0,0 +1,6 @@
|
|||||||
|
import { createRoot } from 'react-dom/client';
|
||||||
|
import MenuApp from './components/MenuApp.jsx'; // Создайте этот файл, если используете React
|
||||||
|
|
||||||
|
const container = document.getElementById('root');
|
||||||
|
const root = createRoot(container);
|
||||||
|
root.render(<MenuApp />);
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
table {
|
||||||
|
|
||||||
|
& td {
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
& tr:nth-child(odd) {
|
||||||
|
background-color: #eeeeee;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#taxi__order-create{
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#taxi__home__filter-form{
|
||||||
|
width: 20%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taxi-btn{
|
||||||
|
margin: 25px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.elem--title.el-title--big{
|
||||||
|
padding: 7px;
|
||||||
|
margin: 50px 0 25px 0;
|
||||||
|
border-left: 5px solid #7864eb;
|
||||||
|
font-size: 1.3rem;
|
||||||
|
background: linear-gradient(90deg, rgb(237 234 255) 0%, rgb(255 255 255) 75%);
|
||||||
|
border-top-left-radius: 5px;
|
||||||
|
border-bottom-left-radius: 5px;
|
||||||
|
display: inline-block;
|
||||||
|
min-width: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-field-block{
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taxi-orders__order-options{
|
||||||
|
|
||||||
|
& button {
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
.order-create__btn-block{
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,387 @@
|
|||||||
|
import { tr } from "date-fns/locale";
|
||||||
|
import React, { useEffect, useState, useMemo, useContext } from "react";
|
||||||
|
import { TaxiOrder_type, TaxiOrder_initial, TaxiOrder_fieldName, TaxiOrder_tableData } from '../types/taxiOrderType';
|
||||||
|
import { differenceInDays } from 'date-fns';
|
||||||
|
import { getCsrfToken } from "../../../../../resources/js/services/getCsrfService";
|
||||||
|
import { Button, TextInput, Select, Option } from '@SharePoint/rencredit_uikit';
|
||||||
|
import { EntityHistoryProps } from "../../../../../resources/js/components/entityHistory/EntityHistory";
|
||||||
|
import { HistoryProvider, HistoryContext } from "../../../../../resources/js/contexts/HistoryContext";
|
||||||
|
import { PopupContext } from "../../../../../resources/js/contexts/PopupContext";
|
||||||
|
import { PreloaderContext } from "../../../../../resources/js/contexts/PreloaderContext";
|
||||||
|
import api from "../../../../../resources/js/api";
|
||||||
|
|
||||||
|
type EmpSupervisorsData = {
|
||||||
|
emp_login: string,
|
||||||
|
emp_supervisor: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function TaxiHome ()
|
||||||
|
{
|
||||||
|
//Массив полей для отображения в таблицах с заяками. Учитывается, в том числе, порядок
|
||||||
|
const rqstTableFields = ['id', 'emp_login', 'emp_supervisor', 'emp_phone', 'taxi_date', 'taxi_time', 'taxi_address_from', 'taxi_address_to', 'cancel_rqst'];
|
||||||
|
//Формируем объект с полями для таблицы
|
||||||
|
const rqstTableHeaderFields: Record<keyof TaxiOrder_tableData, string> = Object.assign({}, ...rqstTableFields.map( field => {return {[field]: TaxiOrder_fieldName[field]}}));
|
||||||
|
const rqstTableHeader:string[] = Object.keys(TaxiOrder_fieldName).map(rqstFieldName => TaxiOrder_fieldName[rqstFieldName]);
|
||||||
|
const [ccEmp, setCcEmp] = useState<string[]>([]);
|
||||||
|
//Стейт для руководителей сотрудников
|
||||||
|
const [empSupervisors, setEmpSupervisors] = useState<EmpSupervisorsData[]>([]);
|
||||||
|
const [allOrders, setAllOrders] = useState<TaxiOrder_type[]>([]);
|
||||||
|
const [filterOrders, setFilterOrders] = useState<TaxiOrder_type[]>([]);
|
||||||
|
const [startSearch, setStartSearch] = useState<boolean>(false);
|
||||||
|
const [rqstNumber, setRqstNumber] = useState<string>('');
|
||||||
|
const [rqstTime, setRqstTime] = useState<string>('');
|
||||||
|
const [rqstLogin, setRqstLogin] = useState<string>('');
|
||||||
|
const [orderTimePeriods, setOrderTimePeriods] = useState<[{time_period: string}]>([{time_period: ''}]);
|
||||||
|
|
||||||
|
const popupContext = useContext(PopupContext);
|
||||||
|
const preloaderContext = useContext(PreloaderContext);
|
||||||
|
|
||||||
|
useEffect ( () => {
|
||||||
|
api.get('/taxi/getTimePeriods',
|
||||||
|
).then(timePeriods_json => setOrderTimePeriods(timePeriods_json.data));
|
||||||
|
|
||||||
|
// fetch('/public/api/taxi/getTimePeriods', {
|
||||||
|
// method: 'GET',
|
||||||
|
// credentials: 'include',
|
||||||
|
// }).then(timePeriods_resp => timePeriods_resp.json().then( timePeriods_json => {
|
||||||
|
// setOrderTimePeriods(timePeriods_json);
|
||||||
|
// }));
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
popupContext.addPopupArrTest([
|
||||||
|
{message: 'для информации', timeOut: true, type: 'attention'}
|
||||||
|
])
|
||||||
|
popupContext.addPopupArrTest([
|
||||||
|
{message: 'ошибка', timeOut: true, type: 'error'}
|
||||||
|
])
|
||||||
|
}, 1000);
|
||||||
|
console.log(Object.keys(TaxiOrder_fieldName))
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
//ГАВРИЛОВ
|
||||||
|
//ЕСЛИ ОБЪЕКТ СО ЗНАЧЕНИЯМИ ДЛЯ ПОИСКА ПУСТОЙ - НЕ ВЫПОЛНЯЕМ ПОИСК, ВОЗВРАЩАЕМ ОПОВЕЩЕНИЕ О ПУСТЫХ УСЛОВИЯХ
|
||||||
|
const getFilterOrders = () => {
|
||||||
|
console.log(rqstTime)
|
||||||
|
console.log(rqstNumber)
|
||||||
|
console.log(rqstLogin)
|
||||||
|
setStartSearch(true);
|
||||||
|
// ГАВРИЛОВ. проверь
|
||||||
|
api.post('/taxi/getFilterOrders', {
|
||||||
|
id: rqstNumber,
|
||||||
|
taxi_time: rqstTime,
|
||||||
|
emp_login: rqstLogin
|
||||||
|
}).then(filterOrdersJson => {
|
||||||
|
setFilterOrders(filterOrdersJson.data);
|
||||||
|
})
|
||||||
|
// fetch('/public/api/taxi/getFilterOrders', {
|
||||||
|
// credentials: 'include',
|
||||||
|
// method: 'POST',
|
||||||
|
// body: JSON.stringify({
|
||||||
|
// id: rqstNumber,
|
||||||
|
// taxi_time: rqstTime,
|
||||||
|
// emp_login: rqstLogin
|
||||||
|
// }),
|
||||||
|
// headers: {
|
||||||
|
// 'content-type': 'application/json'
|
||||||
|
// }
|
||||||
|
// }).then(filterOrdersRqst => filterOrdersRqst.json())
|
||||||
|
// .then(filterOrdersJson => {
|
||||||
|
// setFilterOrders(filterOrdersJson);
|
||||||
|
// })
|
||||||
|
}
|
||||||
|
|
||||||
|
const timePeriodOptions: Option<string>[] = useMemo(() => {
|
||||||
|
return orderTimePeriods.map((time: {time_period: string}) => {
|
||||||
|
return {
|
||||||
|
caption: time.time_period,
|
||||||
|
value: time.time_period,
|
||||||
|
id: time.time_period
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, [orderTimePeriods])
|
||||||
|
|
||||||
|
const empLoginOptions: Option<string>[] = useMemo(() => {
|
||||||
|
return ccEmp.map((empLogin: string) => {
|
||||||
|
return {
|
||||||
|
caption: empLogin,
|
||||||
|
value: empLogin,
|
||||||
|
id: empLogin
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, [ccEmp])
|
||||||
|
|
||||||
|
useEffect ( () => {
|
||||||
|
Promise.all(
|
||||||
|
[
|
||||||
|
// fetch('/public/api/taxi/getEmpInfo', {
|
||||||
|
// credentials: 'include',
|
||||||
|
// method: 'GET',
|
||||||
|
// }).then( empInfo_resp => empInfo_resp.json() ),
|
||||||
|
api.get('taxi/getEmpInfo'),
|
||||||
|
api.get('taxi/getActiveOrders'),
|
||||||
|
// fetch('/public/api/taxi/getActiveOrders', {
|
||||||
|
// credentials: 'include',
|
||||||
|
// method: 'GET',
|
||||||
|
// }).then( allOrders_resp => allOrders_resp.json() )
|
||||||
|
]
|
||||||
|
).then(
|
||||||
|
([
|
||||||
|
{data: empInfo_json},
|
||||||
|
{data: allOrders_json}
|
||||||
|
]) => {
|
||||||
|
setCcEmp(empInfo_json.map( (empInfoEl: {emp_login: String}) => empInfoEl.emp_login ));
|
||||||
|
setAllOrders(allOrders_json);
|
||||||
|
setEmpSupervisors(empInfo_json.map( (empInfoEl: {emp_login: String, emp_group: String}) => ({emp_login: empInfoEl.emp_login, emp_supervisor: empInfoEl.emp_group}) ));
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const isReady = ccEmp.length > 0 && orderTimePeriods.length > 0;
|
||||||
|
|
||||||
|
useEffect ( () => {
|
||||||
|
console.log(!isReady)
|
||||||
|
preloaderContext.setPreloaderVisible(!isReady)
|
||||||
|
// setPreloaderProp(!isReady);
|
||||||
|
// console.log(empSupervisors)
|
||||||
|
}, [isReady])
|
||||||
|
|
||||||
|
if (!ccEmp.length || !orderTimePeriods.length) {
|
||||||
|
//setIsReady(true);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
//setIsReady(false);
|
||||||
|
// console.log(allOrders);
|
||||||
|
console.log(ccEmp);
|
||||||
|
console.log(orderTimePeriods);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ГАВРИЛОВ. ОФОРМИ РЕЗУЛЬТАТЫ ПОИСКА. ПОСЛЕ ПОИСКА ПЛАВНО ОПУСКАЙ ДО ТАБЛИЦЫ РЕЗУЛЬТАТЫ ПОИСКА, ТАКЖЕ ВЫВЕДИ ЗОТЯ БЫ ТЕКСТ "РЕЗУЛЬТАТЫ ПОИСКА, СЕЙЧАС ЭТО ПРОСТО ТАБЛИЦА"
|
||||||
|
|
||||||
|
//Гаврилов
|
||||||
|
//Реализовать подтягивание информации
|
||||||
|
//Реализовать переключение между БД (new and old Magic)
|
||||||
|
|
||||||
|
//console.log(sanctumToken())
|
||||||
|
|
||||||
|
let newDate = new Date('2024-06-05');
|
||||||
|
newDate.setHours(0, 0, 0);
|
||||||
|
|
||||||
|
// function callHistory(entityId) {
|
||||||
|
// console.log(entityId)
|
||||||
|
|
||||||
|
// return fakeObjArr;
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// let resultObj = {
|
||||||
|
// entityId: 1,
|
||||||
|
// entityProps: fakeObjArr
|
||||||
|
// }
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div id='taxi-container'>
|
||||||
|
<Button
|
||||||
|
type = 'button'
|
||||||
|
text = 'Новая заявка'
|
||||||
|
onClick = {
|
||||||
|
() => document.location.href = 'createRqst'
|
||||||
|
}
|
||||||
|
className = "taxi-btn"
|
||||||
|
/>
|
||||||
|
<div className = "elem--title el-title--big">Активные заявки</div>
|
||||||
|
<div className='container__table-block' id='taxi__rqst--active'>
|
||||||
|
<HistoryProvider>
|
||||||
|
<RqstTable
|
||||||
|
allOrders={allOrders}
|
||||||
|
rqstTableHeader={rqstTableHeaderFields}
|
||||||
|
empSupervisors={empSupervisors}
|
||||||
|
/>
|
||||||
|
</HistoryProvider>
|
||||||
|
</div>
|
||||||
|
<div id="taxi__home__filter-form">
|
||||||
|
<div className = "elem--title el-title--big">Поиск заявки</div>
|
||||||
|
<form>
|
||||||
|
<input
|
||||||
|
type="hidden"
|
||||||
|
name="_token"
|
||||||
|
value={getCsrfToken()}
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<TextInput
|
||||||
|
labelText = 'Номер заявки'
|
||||||
|
value = {rqstNumber}
|
||||||
|
onChange = {(e: string) => setRqstNumber(e)}
|
||||||
|
/>
|
||||||
|
{/* <label htmlFor="">Номер заявки</label>
|
||||||
|
<input type="number" onChange={ e => {
|
||||||
|
setRqstNumber(e.target.value)
|
||||||
|
}}></input> */}
|
||||||
|
</div>
|
||||||
|
{/* <div>
|
||||||
|
<label htmlFor="">Дата с</label>
|
||||||
|
<input type="date" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label htmlFor="">Дата по</label>
|
||||||
|
<input type="date" />
|
||||||
|
</div> */}
|
||||||
|
<div>
|
||||||
|
<Select
|
||||||
|
labelText = "Время"
|
||||||
|
options = {timePeriodOptions}
|
||||||
|
size = '1'
|
||||||
|
onChange = { (e: string) => {
|
||||||
|
setRqstTime(e)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{/* <label htmlFor="">Время</label>
|
||||||
|
<select name="taxi_time" id="" onChange={ e => {
|
||||||
|
setRqstTime(e.target.value)
|
||||||
|
}}>
|
||||||
|
<option key='0' value=''></option>
|
||||||
|
{
|
||||||
|
orderTimePeriods.map( (timePeriodEl, timePeriodIndex ) =>
|
||||||
|
<option key={timePeriodIndex++} value={timePeriodEl.time_period}>{timePeriodEl.time_period}</option>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</select> */}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Select
|
||||||
|
labelText = "Сотрудник"
|
||||||
|
options = {empLoginOptions}
|
||||||
|
size = '1'
|
||||||
|
onChange = { (e, selectedOption: {value: string}) => {
|
||||||
|
setRqstLogin(selectedOption.value)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{/* <label htmlFor="">Логин</label>
|
||||||
|
<select onChange={ e => setRqstLogin(e.target.value) }>
|
||||||
|
<option key="0" value=""></option>
|
||||||
|
{
|
||||||
|
ccEmp.map( (empDataEl: string, empDataIndex: number) =>
|
||||||
|
<option key={empDataIndex++} value={empDataEl}>{empDataEl}</option>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</select> */}
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
className = "taxi-btn"
|
||||||
|
type = 'button'
|
||||||
|
text = 'Искать'
|
||||||
|
onClick = { getFilterOrders }
|
||||||
|
size = 's'
|
||||||
|
ui = 'secondary'
|
||||||
|
/>
|
||||||
|
{/* <button type="button" onClick={getFilterOrders}>Искать</button> */}
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div id = "container__filter-rqst-table">
|
||||||
|
{
|
||||||
|
startSearch ?
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
{
|
||||||
|
rqstTableHeader.map( (headEl, headElIndex) =>
|
||||||
|
<th key={headElIndex} className = "table-header">
|
||||||
|
{headEl}
|
||||||
|
</th>)
|
||||||
|
}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{
|
||||||
|
filterOrders.length ?
|
||||||
|
filterOrders.map( (rqstData: TaxiOrder_type, rqstIndex: number) =>
|
||||||
|
<tr key={rqstIndex}>
|
||||||
|
{
|
||||||
|
Object.keys(TaxiOrder_initial).map(initField =>
|
||||||
|
<td>
|
||||||
|
{initField == 'cancel_rqst' ? (rqstData[initField] ? 'Нет' : 'Да') : rqstData[initField]}
|
||||||
|
</td>)
|
||||||
|
}
|
||||||
|
</tr>)
|
||||||
|
: <tr>
|
||||||
|
<td>Запросов не найдено</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
: ''
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function RqstTable(props: {allOrders: TaxiOrder_type[], rqstTableHeader: Record<keyof TaxiOrder_tableData, string>, empSupervisors: EmpSupervisorsData[]}){
|
||||||
|
const historyContext = useContext(HistoryContext);
|
||||||
|
if (!historyContext) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
let newDate = new Date('2024-06-05');
|
||||||
|
newDate.setHours(0, 0, 0);
|
||||||
|
return (
|
||||||
|
props.allOrders.length ?
|
||||||
|
<table className="taxi-orders">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
{
|
||||||
|
Object.entries(props.rqstTableHeader).map((el, index) =>
|
||||||
|
<th key={index} className="table-header">{el[1]}</th>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
<th className = "table-header">Управление</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{
|
||||||
|
props.allOrders.map( (rqstData: TaxiOrder_type, rqstIndex: number) =>
|
||||||
|
<tr key = {rqstIndex}>
|
||||||
|
{
|
||||||
|
Object.entries(props.rqstTableHeader).map( el => {
|
||||||
|
return (
|
||||||
|
// Если поле - руководитель сотрудника - вычисляем значение, ориентируясь на список props.empSupervisors
|
||||||
|
el[0] === 'emp_supervisor' ?
|
||||||
|
<td key={el[0]}>{ props.empSupervisors.find(empData => empData.emp_login == rqstData.emp_login)?.emp_supervisor }</td>
|
||||||
|
: <td key={el[0]}>{ rqstData[el[0]] }</td>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
<td className="taxi-orders__order-options">
|
||||||
|
{/* Можно взаимодействовать только с заявками на такси на сегодняшнюю, либо завтрашнюю дату */}
|
||||||
|
{differenceInDays(new Date(rqstData.taxi_date), new Date()) >= 0 && !rqstData.cancel_rqst ?
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
type = 'button'
|
||||||
|
onClick = { () => { document.location.href = `editOrder/${rqstData.id}` } }
|
||||||
|
text = {'Редактировать'}
|
||||||
|
ui = 'secondaryPurple'
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
type = 'button'
|
||||||
|
onClick = { () => { document.location.href = `cancelRqst/${rqstData.id}` } }
|
||||||
|
text = {'Отменить'}
|
||||||
|
ui = 'secondaryPurple'
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
type = 'button'
|
||||||
|
onClick = { () => { historyContext.getHistoryFromMagic('taxi', rqstData.id, TaxiOrder_fieldName) } }
|
||||||
|
text = {'История'}
|
||||||
|
ui = 'secondaryPurple'
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
: <div>Нет активных заявок</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,635 @@
|
|||||||
|
import React, { useEffect, useContext, useState, useMemo } from "react";
|
||||||
|
import { TaxiOrder_type, TaxiOrder_initial } from '../types/taxiOrderType';
|
||||||
|
import { addDays, format } from 'date-fns';
|
||||||
|
import { getCsrfToken } from "../../../../../resources/js/services/getCsrfService";
|
||||||
|
import { Button, TextInput, Select, Option } from '@SharePoint/rencredit_uikit';
|
||||||
|
import FormValidErr, { FormValidErrObject } from "../../../../../resources/js/components/formValidErr/FormValidErr";
|
||||||
|
import { PopupContext } from "../../../../../resources/js/contexts/PopupContext";
|
||||||
|
import { EntityHistoryProps } from "../../../../../resources/js/components/entityHistory/EntityHistory";
|
||||||
|
import { PreloaderContext } from "../../../../../resources/js/contexts/PreloaderContext";
|
||||||
|
|
||||||
|
//Гаврилов типы для пропсов?
|
||||||
|
// export default function TaxiOrder( {rqstId, setPreloaderProp}: {rqstId: number | undefined, setPreloaderProp: CallableFunction} )
|
||||||
|
export default function TaxiOrder( {rqstId}: {rqstId: number | undefined} )
|
||||||
|
{
|
||||||
|
let newDate = new Date('2024-06-05');
|
||||||
|
newDate.setHours(0, 0, 0);
|
||||||
|
let fakeObjArr: EntityHistoryProps[] = [
|
||||||
|
{
|
||||||
|
changeAction: 'insert',
|
||||||
|
changeAuthor: 'login',
|
||||||
|
changeDate: newDate,
|
||||||
|
changeDetails: [
|
||||||
|
{
|
||||||
|
propName: 'поле',
|
||||||
|
propValue: 'значение'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
propName: 'поле',
|
||||||
|
propValue: 'значение'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
propName: 'поле',
|
||||||
|
propValue: 'значение'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
propName: 'поле2',
|
||||||
|
propValue: 'значение2'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
changeAction: 'insert',
|
||||||
|
changeAuthor: 'login',
|
||||||
|
changeDate: new Date('2024-06-05'),
|
||||||
|
changeDetails: [
|
||||||
|
{
|
||||||
|
propName: 'поле',
|
||||||
|
propValue: 'значение'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
propName: 'поле',
|
||||||
|
propValue: 'значение'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
propName: 'поле',
|
||||||
|
propValue: 'значение'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
propName: 'поле2',
|
||||||
|
propValue: 'значение2'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
changeAction: 'insert',
|
||||||
|
changeAuthor: 'login',
|
||||||
|
changeDate: new Date('2024-06-05'),
|
||||||
|
changeDetails: [
|
||||||
|
{
|
||||||
|
propName: 'поле',
|
||||||
|
propValue: 'значение'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
propName: 'поле',
|
||||||
|
propValue: 'значение'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
propName: 'поле',
|
||||||
|
propValue: 'значение'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
propName: 'поле2',
|
||||||
|
propValue: 'значение2'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
changeAction: 'update',
|
||||||
|
changeAuthor: 'login2',
|
||||||
|
changeDate: new Date('2025-06-05'),
|
||||||
|
changeDetails: [
|
||||||
|
{
|
||||||
|
propName: 'поле3',
|
||||||
|
propValue: 'значение4'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
propName: 'поле3',
|
||||||
|
propValue: 'значение4'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
propName: 'поле3',
|
||||||
|
propValue: 'значение4'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
propName: 'поле3',
|
||||||
|
propValue: 'значение4'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
propName: 'поле5',
|
||||||
|
propValue: 'значение6'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
changeAction: 'update',
|
||||||
|
changeAuthor: 'login2',
|
||||||
|
changeDate: new Date('2025-06-05'),
|
||||||
|
changeDetails: [
|
||||||
|
{
|
||||||
|
propName: 'поле3',
|
||||||
|
propValue: 'значение4'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
propName: 'поле3',
|
||||||
|
propValue: 'значение4'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
propName: 'поле3',
|
||||||
|
propValue: 'значение4'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
propName: 'поле3',
|
||||||
|
propValue: 'значение4'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
propName: 'поле5',
|
||||||
|
propValue: 'значение6'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const preloaderContext = useContext(PreloaderContext);
|
||||||
|
|
||||||
|
//ГАВРИЛОВ ПОСТОЯННЫЙ ПЕРЕРЕНДЕРИНГ СПРОСИТЬ У САШИ. ЭЛЕМЕНТ НЕ МИГАЕТ В КОНСОЛИ, НО ПИШЕТ ПОСТОЯННО ПЕРЕРЕНДЕР
|
||||||
|
console.log('🔁 TaxiForm перерендерился!');
|
||||||
|
interface UserData {
|
||||||
|
emp_id: number,
|
||||||
|
emp_address: string,
|
||||||
|
emp_lastname: string,
|
||||||
|
emp_name: string,
|
||||||
|
emp_surname: string,
|
||||||
|
emp_login: string | null
|
||||||
|
emp_phone: string,
|
||||||
|
//Все остальные поля объекта могут быть пустыми
|
||||||
|
[key: string]: unknown,
|
||||||
|
full_name: string,
|
||||||
|
};
|
||||||
|
const UserData_initial: UserData = {
|
||||||
|
emp_id: 0,
|
||||||
|
emp_address: '',
|
||||||
|
emp_lastname: '',
|
||||||
|
emp_name: '',
|
||||||
|
emp_surname: '',
|
||||||
|
emp_login: '',
|
||||||
|
emp_phone: '',
|
||||||
|
full_name: '',
|
||||||
|
// _token: getCsrfToken()
|
||||||
|
};
|
||||||
|
//Проверка загрузки необходимых для начала работ данных. После успешного получения всех данных происходит рендеринг
|
||||||
|
const [checkLoad, setCheckLoad] = useState(
|
||||||
|
{
|
||||||
|
ccEmp: false,
|
||||||
|
orderData: false,
|
||||||
|
checkEditOrderUserData: false,
|
||||||
|
getTimePeriods: false,
|
||||||
|
checkOfficeAddress: false,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const todayDate = new Date();
|
||||||
|
//Данные по всем пользователям
|
||||||
|
const [ccEmp, setCcEmp] = useState<UserData[]>( [UserData_initial] );
|
||||||
|
//Данные по редактируемому запросу (если вызвано редактирование)
|
||||||
|
const [orderData, setOrderData] = useState<TaxiOrder_type>(TaxiOrder_initial);
|
||||||
|
//Данные по пользователю, чей запрос редактируется (если вызвано редактирование запроса)
|
||||||
|
const [editOrderUserData, setEditOrderUserData] = useState<UserData>(UserData_initial);
|
||||||
|
//Данные по временным промежуткам
|
||||||
|
const [orderTimePeriods, setOrderTimePeriods] = useState< {time_period: string, is_morning_time: number}[] >(
|
||||||
|
[ {time_period: '', is_morning_time: 0} ]
|
||||||
|
);
|
||||||
|
//Массив доступных для заказа такси дат для их дальнейшего преобразования в теги option селекта
|
||||||
|
const [dateOrderArr, setDateOrderArr] = useState<string[]>(
|
||||||
|
[
|
||||||
|
format(todayDate, "yyyy-MM-dd"),
|
||||||
|
format(addDays(todayDate, 1), "yyyy-MM-dd")
|
||||||
|
]
|
||||||
|
);
|
||||||
|
const popupContext = useContext(PopupContext);
|
||||||
|
useEffect ( () => {
|
||||||
|
setFormCreateVisible(true);
|
||||||
|
setFormCreateValidObj([{fieldName: 'testField', fieldErrors: ['errOne']}]);
|
||||||
|
console.log(popupContext)
|
||||||
|
// console.log()
|
||||||
|
// setTimeout(() => {
|
||||||
|
// popupContext.addPopupArrTest([
|
||||||
|
// {message: 'для информации', timeOut: true, type: 'attention'}
|
||||||
|
// ])
|
||||||
|
// }, 1000);
|
||||||
|
// setTimeout(() => {
|
||||||
|
// setPopupArrProp([
|
||||||
|
// {message: 'для информации', timeOut: true, type: 'attention'},
|
||||||
|
// ])
|
||||||
|
// }, 1000);
|
||||||
|
// setTimeout(() => {
|
||||||
|
// setPopupArrProp([
|
||||||
|
// {message: 'для информации', timeOut: false, type: 'info'},
|
||||||
|
// ])
|
||||||
|
// }, 2000);
|
||||||
|
// setTimeout(() => {
|
||||||
|
// setPopupArrProp([
|
||||||
|
// {message: 'для информации', timeOut: false, type: 'info'},
|
||||||
|
// ])
|
||||||
|
// }, 3000);
|
||||||
|
// setPopupArrProp([
|
||||||
|
// {message: 'для информации', timeOut: false, type: 'info'},
|
||||||
|
// {message: 'успешно', timeOut: true, type: 'success'},
|
||||||
|
// {message: 'ошибка', timeOut: true, type: 'error'},
|
||||||
|
// {message: 'обратить внимание', timeOut: true, type: 'attention'}
|
||||||
|
// ])
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const [formCreateVisible, setFormCreateVisible] = useState<boolean>(false);
|
||||||
|
const [formCreateValidErrObj, setFormCreateValidObj] = useState<FormValidErrObject[]>([{fieldName: null, fieldErrors: []}])
|
||||||
|
|
||||||
|
//ГАВРИЛОВ ДОБАВИТЬ ВСПЛЫВАЮЩЕЕ ОКНО ЕСЛИ ПРОИСХОДИТ НЕСООТВЕТСТВИЕ ВРЕМЕНИ И ДАТЫ ЗАКАЗА ТАКСИ? А НЕ ПРОСТО УДАЛЯТЬ ЗНАЧЕНИЕ ИЗ СОСЕДНЕГО ПОЛЯ?
|
||||||
|
|
||||||
|
//Адреса офисов
|
||||||
|
const [officeAddressInfo, setOfficeAddressInfo] = useState< {place: string, address: string}[] >(
|
||||||
|
[ {place: '', address: ''} ]
|
||||||
|
);
|
||||||
|
//Адрес офиса, где работает сотрудник. Определяется на этапе выбора логина
|
||||||
|
const [empOfficeAddress, setEmpOfficeAddress] = useState<string | null>(null);
|
||||||
|
//const [orderTime, setOrderTime] = useState<string|null>(null);
|
||||||
|
//const [orderDate, setOrderDate] = useState<string|null>(null);
|
||||||
|
// const [orderAddressFrom, setOrderAddressFrom] = useState<string|null>(null);
|
||||||
|
// const [orderAddressTo, setOrderAddressTo] = useState<string|null>(null);
|
||||||
|
|
||||||
|
function gotoHome()
|
||||||
|
{
|
||||||
|
document.location.href = '/public/taxi/home';
|
||||||
|
}
|
||||||
|
|
||||||
|
//Гаврилов. Не передаешь CSRF токен
|
||||||
|
//Отправка заказа на такси
|
||||||
|
function sendTaxiOrder ()
|
||||||
|
{
|
||||||
|
console.log(orderData)
|
||||||
|
console.log(editOrderUserData)
|
||||||
|
//return
|
||||||
|
// setPreloaderProp(true, 'создаем заявку')
|
||||||
|
preloaderContext.setPreloaderVisible(true);
|
||||||
|
preloaderContext.setPreloaderText('создаем заявку');
|
||||||
|
let popupType;
|
||||||
|
fetch('/public/api/taxi/' + (rqstId ? `editOrder/${rqstId}` : 'createRqst'), {
|
||||||
|
credentials: 'include',
|
||||||
|
method: (rqstId ? "PATCH" : "POST"),
|
||||||
|
body: JSON.stringify(orderData),
|
||||||
|
headers: {
|
||||||
|
'content-type': 'application/json',
|
||||||
|
'Accept': 'application/json'
|
||||||
|
}
|
||||||
|
}).then(result => {
|
||||||
|
preloaderContext.setPreloaderVisible(false);
|
||||||
|
// setPreloaderProp(false)
|
||||||
|
result.json().then(jsonResult => {
|
||||||
|
console.log(jsonResult)
|
||||||
|
if (!result.ok) {
|
||||||
|
//ГАВРИЛОВ здесь обработка ошибок валидации формы
|
||||||
|
if (result.status == 422) {
|
||||||
|
// setPopupArrProp(
|
||||||
|
// [
|
||||||
|
// //ГАВРИЛОВ обработка ошибки
|
||||||
|
// {message: 'Произошла ошибка! Заявка не создана', type: 'error'},
|
||||||
|
// ]
|
||||||
|
// )
|
||||||
|
} else {
|
||||||
|
// setPopupArrProp(
|
||||||
|
// [
|
||||||
|
// //ГАВРИЛОВ обработка ошибки
|
||||||
|
// {message: jsonResult.result_msg, type: 'error'},
|
||||||
|
// ]
|
||||||
|
// )
|
||||||
|
}
|
||||||
|
popupType = 'error'
|
||||||
|
} else {
|
||||||
|
popupType = 'success'
|
||||||
|
}
|
||||||
|
popupContext.addPopupArrTest(
|
||||||
|
[
|
||||||
|
{message: jsonResult.message, type: popupType},
|
||||||
|
]
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//Функция, собирающая нужный массив для формирования из него списка option для select
|
||||||
|
function transformToOptionsFunc <T,>(
|
||||||
|
dataArr: T[],
|
||||||
|
dataKey?: keyof T
|
||||||
|
): Option<string>[] {
|
||||||
|
let optionArr = dataArr.map(item => {
|
||||||
|
//Без проверки ниже, Typescript ругается на условный атрибут dataKey, который может отсутствовать, но при этом укаан как относящийся к Дженерику
|
||||||
|
const value = dataKey !== undefined
|
||||||
|
? item[dataKey]
|
||||||
|
: item;
|
||||||
|
|
||||||
|
return {
|
||||||
|
caption: String(value),
|
||||||
|
value: String(value),
|
||||||
|
id: String(value)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return optionArr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Метод проверки соответствует ли дата и время заказа логике. Наприме, если дата заказа сегодняшняя - нельзя выбрать утренний промежуток времени
|
||||||
|
* @param orderTime время заказа такси
|
||||||
|
* @param orderDate дата заказа такси
|
||||||
|
* @returns результат проверки соответствия даты и времени заказа
|
||||||
|
*/
|
||||||
|
function checkTimeAndDate (orderTime: string|null, orderDate: string|null): boolean
|
||||||
|
{
|
||||||
|
// console.log(orderTime)
|
||||||
|
// console.log(!orderTime)
|
||||||
|
// console.log(orderDate)
|
||||||
|
// console.log(!orderDate)
|
||||||
|
if (!orderTime || !orderDate) {
|
||||||
|
//console.log(1)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
let isMorningTimeCheck = orderTimePeriods.filter( e => e.time_period == orderTime )[0].is_morning_time;
|
||||||
|
// console.log(isMorningTimeCheck)
|
||||||
|
//Если выбранная дата заказа больше текущей - заказ на завтра, можно выбирать любую дату
|
||||||
|
if (!(new Date(orderDate) > todayDate)) {
|
||||||
|
//console.log(2)
|
||||||
|
return !isMorningTimeCheck;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// const ccEmpList: Option<string>[] = useMemo(() => {
|
||||||
|
// return ccEmp.map(empData => {
|
||||||
|
// return {
|
||||||
|
// caption: empData.emp_login,
|
||||||
|
// value: empData.emp_login,
|
||||||
|
// id: empData.emp_login
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// }, [ccEmp]);
|
||||||
|
|
||||||
|
// console.log(ccEmpList)
|
||||||
|
|
||||||
|
|
||||||
|
const ccEmpList = useMemo( () => {
|
||||||
|
return transformToOptionsFunc(ccEmp, 'emp_login');
|
||||||
|
}, [ccEmp]);
|
||||||
|
|
||||||
|
const orderDateList = useMemo( () => {
|
||||||
|
return transformToOptionsFunc(dateOrderArr);
|
||||||
|
}, [dateOrderArr]);
|
||||||
|
|
||||||
|
const orderTimeList = useMemo( () => {
|
||||||
|
return transformToOptionsFunc(orderTimePeriods, 'time_period')
|
||||||
|
}, [orderTimePeriods]);
|
||||||
|
|
||||||
|
//Загрузка данных для старта работ
|
||||||
|
useEffect ( () => {
|
||||||
|
//Получаем информацию по сотруднику при загрузке страницы
|
||||||
|
fetch('/public/api/taxi/getEmpInfo', {
|
||||||
|
credentials: 'include',
|
||||||
|
method: 'GET',
|
||||||
|
// headers: new Headers({
|
||||||
|
// 'Authorization': `Bearer ${sanctumToken()}`
|
||||||
|
// })
|
||||||
|
}).then(empInfo_resp => empInfo_resp.json().then(empInfo_json => {
|
||||||
|
console.log(empInfo_json)
|
||||||
|
console.log(editOrderUserData)
|
||||||
|
setCcEmp(empInfo_json);
|
||||||
|
setCheckLoad(loadObj => ( {...loadObj, ccEmp: true} ));
|
||||||
|
}));
|
||||||
|
//Получаем доступные временные промежутки для заказа такси
|
||||||
|
fetch('/public/api/taxi/getTimePeriods', {
|
||||||
|
method: 'GET',
|
||||||
|
credentials: 'include',
|
||||||
|
// headers: new Headers({
|
||||||
|
// 'Authorization': `Bearer ${sanctumToken()}`
|
||||||
|
// })
|
||||||
|
}).then(timePeriods_resp => timePeriods_resp.json().then(timePeriods_json => {
|
||||||
|
setOrderTimePeriods(timePeriods_json);
|
||||||
|
setCheckLoad(loadObj => ( {...loadObj, getTimePeriods: true} ));
|
||||||
|
}));
|
||||||
|
//ГАВРИЛОВ. ВЕЗДЕ В FETCH ЗАПРОСАХ ПЕРЕХВАТЫВАЙ ОШИБКИ И ВЫВОДИ СООБЩЕНИЯ ОБ ОШИБКЕ. НАПРИМЕМР С 401. В ЭТОМ СЛУЧАЕ НУЖНО ПЕРЕБРАСЫВАТЬ ПОЛЬЗОВАТЕЛЯ НА СТРАНИЦУ АУТЕНТИФИКАЦИИ
|
||||||
|
//Получае адреса всех офисов, куда могут заказываться такси?
|
||||||
|
fetch('/public/api/taxi/getOfficeAddress', {
|
||||||
|
method: 'GET',
|
||||||
|
credentials: 'include',
|
||||||
|
}).then(officeAddress_resp => {officeAddress_resp.json().then(officeAddress_json => {
|
||||||
|
setOfficeAddressInfo(officeAddress_json);
|
||||||
|
setCheckLoad(loadObj => ( {...loadObj, checkOfficeAddress: true} ));
|
||||||
|
})});
|
||||||
|
//Если в пропсах передается rqstId, происходит редактирование заявки, а не создание новой - получаем данные по редактируемой заявке на такси
|
||||||
|
if (rqstId) {
|
||||||
|
fetch(`/public/api/taxi/getOrderById/${rqstId}`, {
|
||||||
|
method: 'GET',
|
||||||
|
credentials: 'include',
|
||||||
|
// headers: new Headers({
|
||||||
|
// 'Authorization': `Bearer ${sanctumToken()}`
|
||||||
|
// })
|
||||||
|
}).then(orderData_resp => orderData_resp.json().then( orderData_json => {
|
||||||
|
console.log(orderData_json)
|
||||||
|
setOrderData(orderData_json);
|
||||||
|
setCheckLoad(loadObj => ({...loadObj, orderData: true}));
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
//гаврилов. Нужно ввести объект с данными по запросу и туда класть только нужные данные , а не все параметры пользователя. и тогда не нужно нигде проверять rqstId. Внизу в методе класть в этот объект все нужные параметры
|
||||||
|
|
||||||
|
useEffect ( () => {
|
||||||
|
//Гаврилов. Причем тут проверка логина? Зачем она?
|
||||||
|
if (rqstId && orderData.emp_login) {
|
||||||
|
//Если передан id запроса на редактирование, устанавливаем значение с данными пользователя редактируемого запроса
|
||||||
|
fetch(`/public/api/taxi/getEmpInfo/${orderData.emp_login}`).then(userData_resp => userData_resp.json().then(userData_json => {
|
||||||
|
//гаврилов. Вот здесь нужно класть данные в orderData, а также заполнять адрес из и адрес куда
|
||||||
|
setEditOrderUserData(userData_json[0]);
|
||||||
|
//setOrderData(prevData => ({...prevData, userData_json[0]}));
|
||||||
|
//setEmpAddress(editOrderUserData['emp_address']);
|
||||||
|
setCheckLoad(loadObj => ( {...loadObj, checkEditOrderUserData: true} ));
|
||||||
|
//ГАВРИЛОВ. вынеси в отедльную функцию определение адреса офиса?
|
||||||
|
setEmpOfficeAddress(officeAddressInfo.filter(addressInfo => addressInfo.place == userData_json[0].emp_area)[0].address);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}, [orderData.emp_login])
|
||||||
|
|
||||||
|
//Итоговая проверка все ли необходимые данные для рендеринга получены
|
||||||
|
const isReady = rqstId ?
|
||||||
|
checkLoad.ccEmp && checkLoad.checkEditOrderUserData && checkLoad.orderData && checkLoad.checkOfficeAddress && checkLoad.getTimePeriods
|
||||||
|
: checkLoad.ccEmp;
|
||||||
|
|
||||||
|
//Регулировка видимости прелоадера в зависимости от того все ли данные для рендеринга получены или нет
|
||||||
|
useEffect ( () => {
|
||||||
|
//isReady ? setPreloaderProp(false) : setPreloaderProp(true);
|
||||||
|
isReady ? preloaderContext.setPreloaderVisible(false) : preloaderContext.setPreloaderVisible(true);
|
||||||
|
}, [isReady])
|
||||||
|
|
||||||
|
if (!isReady) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div id = "taxi__order-create">
|
||||||
|
{/* <EntityHistory
|
||||||
|
entityId={1}
|
||||||
|
entityProps= {fakeObjArr}
|
||||||
|
/> */}
|
||||||
|
<div className = "order-create__btn-block">
|
||||||
|
<Button
|
||||||
|
type = 'button'
|
||||||
|
onClick = {gotoHome}
|
||||||
|
text = 'Домой'
|
||||||
|
ui = 'secondary'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<h2>{rqstId ? 'Редактирование' : 'Создание'} заявки на такси</h2>
|
||||||
|
<div className="form-container form-container--medium-size form-containter--left-pos">
|
||||||
|
{/* <FormValidErr
|
||||||
|
visible = {formCreateVisible}
|
||||||
|
validErrorsObj = {formCreateValidErrObj}
|
||||||
|
/> */}
|
||||||
|
<form>
|
||||||
|
{/* ГАВРИЛОВ как защищаешься от csrf если комментируешь поле ниже? */}
|
||||||
|
{/* <input
|
||||||
|
type="hidden"
|
||||||
|
name="_token"
|
||||||
|
value={getCsrfToken()}
|
||||||
|
/> */}
|
||||||
|
<div className="form__field-block">
|
||||||
|
<Select
|
||||||
|
//ГАВРИЛОВ. ПЕРЕПИШИ НА ОПРЕДЕЛЕНИЕ НАЗВАНИЯ ПОЛЯ, СОГЛАСНО TaxiOrder_fieldName ИЗ TAXIORDERTYPE
|
||||||
|
labelText = 'Дата заказа'
|
||||||
|
options = {orderDateList}
|
||||||
|
//Гаврилов. Может где-то сверху нужно класть в объект с данными формы данные из orderData (если она есть) .тогда не нужно проверять props.rqstId ?
|
||||||
|
value = {orderData.taxi_date ? orderDateList.find(dateData => dateData.value === orderData.taxi_date) : null}
|
||||||
|
size = 'm'
|
||||||
|
onChange = {
|
||||||
|
(_, sel:{caption:string, id:string, value:string} ) => {
|
||||||
|
let selOrderDate: string|null = (sel ? sel.value : null);
|
||||||
|
//setEditOrderUserData(prevData => ({...prevData, taxi_date: selOrderDate}));
|
||||||
|
setOrderData(prevData => ( {...prevData, taxi_date: selOrderDate} ));
|
||||||
|
//Если проверка соответствия времени и даты заказа не выполняется, сбрасываем время.
|
||||||
|
// if (!checkTimeAndDate(orderData.taxi_time, selOrderDate)) {
|
||||||
|
popupContext.addPopupArrTest( [{message: 'Несоответствие времени и даты', type: 'error'}] )
|
||||||
|
// setOrderData(prevData => ( {...prevData, taxi_time: null} ));
|
||||||
|
// }
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="form__field-block">
|
||||||
|
<Select
|
||||||
|
labelText = "Время заказа"
|
||||||
|
options = {orderTimeList}
|
||||||
|
value = {orderData.taxi_time ? orderTimeList.find(dateData => dateData.value === orderData.taxi_time) : null}
|
||||||
|
size = 'm'
|
||||||
|
onChange = {(_, sel:{caption:string, id:string, value:string}) => {
|
||||||
|
let selOrderTime = (sel ? sel.value : null);
|
||||||
|
setOrderData(prevData => ( {...prevData, taxi_time: selOrderTime} ));
|
||||||
|
//Проверяем относится ли выбранный промежуток времени заказа к утру или нет. Если выбран утренний промежуток, дата откуда - адрес сотрудника, адрес куда - офис, если выбран вечерний промежуток - наоборот
|
||||||
|
if (orderTimePeriods.filter( e => selOrderTime == e.time_period )[0].is_morning_time == 1) {
|
||||||
|
console.log(1)
|
||||||
|
setOrderData(prevData => ( {...prevData, taxi_address_from: editOrderUserData.emp_address, taxi_address_to: empOfficeAddress} ));
|
||||||
|
} else {
|
||||||
|
console.log(2)
|
||||||
|
console.log(empOfficeAddress)
|
||||||
|
setOrderData(prevData => ( {...prevData, taxi_address_from: empOfficeAddress, taxi_address_to: editOrderUserData.emp_address} ));
|
||||||
|
}
|
||||||
|
//Если проверка соответствия и времени заказа не выполняется, сбрасываем дату
|
||||||
|
if (!checkTimeAndDate(selOrderTime, orderData.taxi_date)) {
|
||||||
|
popupContext.addPopupArrTest(
|
||||||
|
[{message: 'Несоответствие времени и даты', type: 'error'}]
|
||||||
|
)
|
||||||
|
setOrderData(prevData => ({...prevData, taxi_date: null}));
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="form__field-block">
|
||||||
|
<Select
|
||||||
|
labelText = 'Логин сотрудника'
|
||||||
|
options = {ccEmpList}
|
||||||
|
value = {orderData.emp_login}
|
||||||
|
size = 'm'
|
||||||
|
//В компоненте Select значение "выбранного" option помещается во второй аргумент onChange
|
||||||
|
onChange = { (_, sel:{caption:string, id:string, value:string}) => {
|
||||||
|
if (sel) {
|
||||||
|
let empData = ccEmp.filter(empData => {return empData.emp_login == sel.value})[0];
|
||||||
|
//При создании нового запроса, на этом действии время и дата могут быть уже записаны в объект editOrderUserData, но при выборе нового логина, если передать в сеттер setEditOrderUserData только объект empData, он перезапишет значения времени и даты, поэтому конкатенируем объект, отдавая приоритет при замене дублирующих значений empData (правый объект перезапишет левый)
|
||||||
|
setEditOrderUserData( {...editOrderUserData, ...empData} );
|
||||||
|
setOrderData(prevData => ({...prevData, emp_login: sel.value, emp_phone: empData.emp_phone}));
|
||||||
|
//Гаврилов. Если площадка РКЦ - выводить ошибку? Так как у этой площадки нет адреса офиса
|
||||||
|
//ГАВРИЛОВ. ВЫНЕСИ ОПРЕДЕЛЕНИЕ АДРЕСА В ОТДЕЛЬНУЮ ФУНКЦИЮ?
|
||||||
|
let officeAddress: string | null = empData.emp_area == 'РКЦ' ? null : officeAddressInfo.filter(addressInfo => addressInfo.place == empData.emp_area)[0].address;
|
||||||
|
setEmpOfficeAddress(officeAddress);
|
||||||
|
setOrderData(prevData => {
|
||||||
|
let setAddressTo: string|null, setAddressFrom: string|null;
|
||||||
|
//Если время выставлено в форме
|
||||||
|
if (orderData.taxi_time) {
|
||||||
|
//Проверяем относится ли выбранный промежуток времени заказа к утру или нет. Если выбран утренний промежуток, дата откуда - адрес сотрудника, адрес куда - офис, если выбран вечерний промежуток - наоборот
|
||||||
|
if (orderTimePeriods.filter( e => orderData.taxi_time == e.time_period )[0].is_morning_time == 1) {
|
||||||
|
setAddressTo = officeAddress;
|
||||||
|
setAddressFrom = empData.emp_address;
|
||||||
|
} else {
|
||||||
|
setAddressTo = empData.emp_address;
|
||||||
|
setAddressFrom = officeAddress;
|
||||||
|
}
|
||||||
|
//Если время заказа не выбрано, сбрасываем дату откуда и дату куда
|
||||||
|
} else {
|
||||||
|
setAddressTo = null;
|
||||||
|
setAddressFrom = null;
|
||||||
|
}
|
||||||
|
return {...prevData, taxi_address_from: setAddressFrom, taxi_address_to: setAddressTo};
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setOrderData(prevData => ({...prevData, emp_login: null, emp_phone: null}));
|
||||||
|
setEditOrderUserData(UserData_initial);
|
||||||
|
setEmpOfficeAddress(null);
|
||||||
|
setOrderData(prevData => ({...prevData, taxi_address_from: null, taxi_address_to: null}));
|
||||||
|
}
|
||||||
|
} }
|
||||||
|
//При редактировании существующего запроса нельзя менять выбранный логин сотрудника для заказа
|
||||||
|
disabled = {rqstId ? true : false}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="form__field-block">
|
||||||
|
<TextInput
|
||||||
|
labelText = 'ФИО'
|
||||||
|
value = {editOrderUserData.full_name}
|
||||||
|
disabled = {true}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="form__field-block">
|
||||||
|
<TextInput
|
||||||
|
labelText = 'Мобильный номер телефона'
|
||||||
|
value = {orderData.emp_phone}
|
||||||
|
onChange = {(e: string) => {
|
||||||
|
setOrderData(prevData => ({...prevData, emp_phone: e}));
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="form__field-block">
|
||||||
|
<TextInput
|
||||||
|
labelText = 'Адрес (откуда)'
|
||||||
|
value = {
|
||||||
|
//Если в пропсы передается id запроса, проставляем значение из параметров имеющегося запроса. В противном случае определяем является ли выбранный временной промежуток утренним. Если да - прописываем, что едем из адреса сотрудника, в противном случае - из офиса
|
||||||
|
//Гаврилов. Будет ли при редактировании уже созданного запроса, работать смена адресов при изменении времени запроса? Или всегда будет искаться props.rqstId и логика будет исходить из этого?
|
||||||
|
orderData.taxi_address_from
|
||||||
|
}
|
||||||
|
onChange = { (e: string) => {
|
||||||
|
setOrderData(prevData => ({...prevData, taxi_address_from: e}));
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className = "form__field-block">
|
||||||
|
<TextInput
|
||||||
|
labelText = 'Адрес (куда)'
|
||||||
|
value = {orderData.taxi_address_to}
|
||||||
|
onChange = {(e: string) => {
|
||||||
|
setOrderData(prevData => ({...prevData, taxi_address_to: e}));
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className = "order-create__btn-block">
|
||||||
|
<Button
|
||||||
|
type = 'button'
|
||||||
|
onClick = {sendTaxiOrder}
|
||||||
|
text = 'Отправить'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { createRoot } from 'react-dom/client';
|
||||||
|
import { AppProvider } from '../../../../../resources/js/providers/AppProvider.tsx';
|
||||||
|
import TaxiHome from '../components/TaxiHome.tsx';
|
||||||
|
|
||||||
|
const container:HTMLElement = document.getElementById('root')!;
|
||||||
|
const root = createRoot(container);
|
||||||
|
|
||||||
|
root.render(
|
||||||
|
<AppProvider>
|
||||||
|
<TaxiHome/>
|
||||||
|
</AppProvider>
|
||||||
|
);
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import { createRoot } from 'react-dom/client';
|
||||||
|
import React from 'react';
|
||||||
|
import '@SharePoint/rencredit_uikit/dist/static/fonts/mont/Mont.css';
|
||||||
|
import { AppProvider } from '../../../../../resources/js/providers/AppProvider.tsx';
|
||||||
|
import TaxiOrder from '../components/TaxiOrder.tsx';
|
||||||
|
|
||||||
|
const container:HTMLElement = document.getElementById('root')!;
|
||||||
|
const root = createRoot(container);
|
||||||
|
|
||||||
|
//ГАВРИЛОВ
|
||||||
|
//не забудь обернуть рендер editOrder так же в PopupProvider. И вообще это дубирование выглядит костыльно
|
||||||
|
|
||||||
|
//Гаврилов
|
||||||
|
//Спроси у дипсика насколько корректно таким образом получать аргументы из URLA
|
||||||
|
if (document.location.pathname.split('/').find(el => el === 'editOrder')) {
|
||||||
|
let rqstIdUrl = parseInt(document.location.pathname.split('/').pop());
|
||||||
|
root.render(
|
||||||
|
<AppProvider>
|
||||||
|
<TaxiOrder
|
||||||
|
rqstId = {rqstIdUrl}
|
||||||
|
/>
|
||||||
|
</AppProvider>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
root.render(
|
||||||
|
<AppProvider>
|
||||||
|
{/* Не получится передавать контейнер попапов на этом этапе, так как компоненты приложения (формы Такси) должны иметь общего родителя с компонентом контейнеров попапов, иначе они не смогут знать через общий стейт какое состояние у набора попапов */}
|
||||||
|
{/* ГАВРИЛОВ ругается на указание параметра rqstId в TaxiPage? */}
|
||||||
|
{/* <TaxiOrderPage rqstId = {undefined}/> */}
|
||||||
|
<TaxiOrder
|
||||||
|
rqstId = {undefined}
|
||||||
|
/>
|
||||||
|
</AppProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
/**
|
||||||
|
* Объект заказа такси
|
||||||
|
*/
|
||||||
|
export interface TaxiOrder_type{
|
||||||
|
id: number | null,
|
||||||
|
emp_login: string | null,
|
||||||
|
emp_phone: string | null,
|
||||||
|
taxi_date: string | null,
|
||||||
|
taxi_time: string | null,
|
||||||
|
taxi_address_from: string | null,
|
||||||
|
taxi_address_to: string | null,
|
||||||
|
cancel_rqst: boolean
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Тип для отображения данных по заявке на такси в таблице (есть дополнительные поля чисто для отображения)
|
||||||
|
*/
|
||||||
|
export type TaxiOrder_tableData = TaxiOrder_type & {
|
||||||
|
emp_supervisor: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Начальное состояние типа заказа такси
|
||||||
|
*/
|
||||||
|
export const TaxiOrder_initial: TaxiOrder_type = {
|
||||||
|
id: null,
|
||||||
|
emp_login: null,
|
||||||
|
emp_phone: null,
|
||||||
|
taxi_date: null,
|
||||||
|
taxi_time: null,
|
||||||
|
taxi_address_from: null,
|
||||||
|
taxi_address_to: null,
|
||||||
|
cancel_rqst: false
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Справочник названий полей запроса такси
|
||||||
|
* гаврилов. пересекается со свойством TaxiMain с названием полей. ПОПРАВИТЬ, РЕАЛИЗОВАВ ОБМЕН ТИПАМИ ЧЕРЕЗ СТОРОННИЙ ПАКЕТ
|
||||||
|
*/
|
||||||
|
export const TaxiOrder_fieldName = {
|
||||||
|
id: 'Номер запроса',
|
||||||
|
emp_login: 'Логин сотрудника',
|
||||||
|
emp_supervisor: 'Руководитель',
|
||||||
|
emp_phone: 'Телефон сотрудника',
|
||||||
|
taxi_date: 'Дата заказа',
|
||||||
|
taxi_time: 'Время заказа',
|
||||||
|
taxi_address_from: 'Адрес (откуда)',
|
||||||
|
taxi_address_to: 'Адрес (куда)',
|
||||||
|
cancel_rqst: 'Запрос актуален'
|
||||||
|
};
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
@extends('taxi::layouts.master')
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<h1>Hello World</h1>
|
||||||
|
|
||||||
|
<p>Module: {!! config('taxi.name') !!}</p>
|
||||||
|
@endsection
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
||||||
|
|
||||||
|
<!-- ГАВРИЛОВ. НЕ УВЕРЕН, ЧТО ЭТО НУЖНО -->
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
|
||||||
|
<title>Taxi Module - {{ config('app.name', 'Laravel') }}</title>
|
||||||
|
|
||||||
|
<meta name="description" content="{{ $description ?? '' }}">
|
||||||
|
<meta name="keywords" content="{{ $keywords ?? '' }}">
|
||||||
|
<meta name="author" content="{{ $author ?? '' }}">
|
||||||
|
|
||||||
|
<!-- Fonts -->
|
||||||
|
<link rel="preconnect" href="https://fonts.bunny.net">
|
||||||
|
<link href="https://fonts.bunny.net/css?family=figtree:400,500,600&display=swap" rel="stylesheet" />
|
||||||
|
|
||||||
|
{{-- Vite CSS --}}
|
||||||
|
{{-- {{ module_vite('build-taxi', 'resources/assets/sass/app.scss') }} --}}
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
@yield('content')
|
||||||
|
|
||||||
|
{{-- Vite JS --}}
|
||||||
|
{{-- {{ module_vite('build-taxi', 'resources/assets/js/app.js') }} --}}
|
||||||
|
</body>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
@extends('layouts.app_main')
|
||||||
|
|
||||||
|
@section('app_styles')
|
||||||
|
@vite(['Modules/Taxi/resources/css/taxiHome.css'])
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('app_content')
|
||||||
|
<div id="root"></div>
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('app_scripts')
|
||||||
|
@vite(['Modules/Taxi/resources/js/page/taxiHomePage.tsx'])
|
||||||
|
@endsection
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
@extends('layouts.app_main')
|
||||||
|
|
||||||
|
@section('app_styles')
|
||||||
|
@vite(['Modules/Taxi/resources/css/taxiOrder.css'])
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('app_content')
|
||||||
|
<div id="root"></div>
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('app_scripts')
|
||||||
|
@vite(['Modules/Taxi/resources/js/page/taxiOrderPage.tsx'])
|
||||||
|
@endsection
|
||||||
Reference in New Issue
Block a user