date pickers

This commit is contained in:
merelendor 2021-12-02 16:40:47 +03:00
parent 782d798056
commit 8348004f49
29 changed files with 979 additions and 3339 deletions

View File

@ -134,7 +134,7 @@ export const getContractRegistration = ({ dispatch, number, }) =>
})
.then((response) =>
{
dispatch({ type: actionTypes.CONTRACT_HELPCARD, data: { registration: response.data } });
dispatch({ type: actionTypes.CONTRACT_REGISTRATION, data: { registration: response.data } });
resolve();
})

View File

@ -23,7 +23,7 @@ if(process.browser)
};
}
export const getContractsList = ({ dispatch, order = "date", sort = "desc", page = 1, search, date_from, date_to }) =>
export const getContractsList = ({ dispatch, order = "date", sort = "desc", page = 1, search, date_from, date_to, all }) =>
{
const page_size = 5;
@ -46,8 +46,8 @@ export const getContractsList = ({ dispatch, order = "date", sort = "desc", page
if(search !== undefined && search !== null && search !== "")
{
query = query.where([["number", "LIKE", `%${ search }%`], "OR", ["car.reg_number", "LIKE", `%${ search }%`], "OR", ["car.vin_number", "LIKE", `%${ search }%`]]);
query_total = query_total.where([["number", "LIKE", `%${ search }%`], "OR", ["car.reg_number", "LIKE", `%${ search }%`], "OR", ["car.vin_number", "LIKE", `%${ search }%`]])
query = query.where([["number", "LIKE", `%${ search }%`], "OR", ["car.reg_number", "LIKE", `%${ search }%`], "OR", ["car.vin_number", "LIKE", `%${ search }%`], "OR", ["car.brand.name", "LIKE", `%${ search }%`], "OR", ["car.model.name", "LIKE", `%${ search }%`]]);
query_total = query_total.where([["number", "LIKE", `%${ search }%`], "OR", ["car.reg_number", "LIKE", `%${ search }%`], "OR", ["car.vin_number", "LIKE", `%${ search }%`], "OR", ["car.brand.name", "LIKE", `%${ search }%`], "OR", ["car.model.name", "LIKE", `%${ search }%`]])
}
/*
@ -58,7 +58,14 @@ export const getContractsList = ({ dispatch, order = "date", sort = "desc", page
}
*/
query = query.orderBy(orderBy).limit(page_size).offset(offset);
if(all)
{
query = query.orderBy(orderBy);
}
else
{
query = query.orderBy(orderBy).limit(page_size).offset(offset);
}
query_total.exec().then((total_rows) =>
{

95
actions/fileActions.js Normal file
View File

@ -0,0 +1,95 @@
import axios from 'axios';
import { Cookies } from 'react-cookie';
import Router from 'next/router';
import moment from 'moment';
import fileDownload from 'js-file-download';
import * as actionTypes from '../constants/actionTypes';
if(process.browser)
{
FormData.prototype.appendObject = function(obj, namespace)
{
let keyName;
for (var key in obj)
{
if (obj.hasOwnProperty(key))
{
keyName = [namespace, '[', key, ']'].join('');
this.append(keyName, obj[key]);
}
}
};
}
export const getFile = ({ id, filename }) =>
{
console.log("getFile");
return new Promise((resolve, reject) =>
{
axios.get(`${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/file/download`, {
params: { id },
responseType: 'blob',
})
.then((response) =>
{
fileDownload(response.data, filename);
resolve();
})
.catch((error) =>
{
console.log("error");
console.error(error);
reject();
});
});
}
export const getPrintFile = ({ contract, num, type, date, filename }) =>
{
console.log("getFile");
return new Promise((resolve, reject) =>
{
axios.get(`${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/file/print-form`, {
params: { contract, num, type, date },
responseType: 'blob',
})
.then((response) =>
{
fileDownload(response.data, filename);
resolve();
})
.catch((error) =>
{
console.log("error");
console.error(error);
reject();
});
});
}
export const getReconciliationFile = ({ contract, date_from, date_to, filename }) =>
{
console.log("getFile");
return new Promise((resolve, reject) =>
{
axios.get(`${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/file/reconciliation`, {
params: { contract, date_from, date_to, },
responseType: 'blob',
})
.then((response) =>
{
fileDownload(response.data, filename);
resolve();
})
.catch((error) =>
{
console.log("error");
console.error(error);
reject();
});
});
}

View File

@ -3,3 +3,4 @@ export * from './contractsActions';
export * from './contractActions';
export * from './calendarActions';
export * from './companyActions';
export * from './fileActions';

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1607,6 +1607,7 @@ main {
display: flex;
align-items: center;
justify-content: space-between;
cursor: pointer;
p {
margin-bottom: 0;
@ -3006,8 +3007,22 @@ main {
opacity: 0.4;
}
&.payment {
background: var(--green);
border: 1px solid var(--green);
.cell_header {
color: #fff;
span {color: inherit;}
}
.cell_body p {color: #fff;}
}
&.current {
background: var(--blue);
background: var(--blue)!important;
border: 1px solid var(--blue)!important;
.cell_header {
color: #fff;

View File

@ -14,6 +14,7 @@
"axios": "^0.24.0",
"cookie": "^0.4.1",
"cors": "^2.8.5",
"js-file-download": "^0.4.12",
"jsonwebtoken": "^8.5.1",
"moment": "^2.29.1",
"next": "11.1.2",

View File

@ -0,0 +1,52 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import axios from 'axios';
import { Cookies } from 'react-cookie';
import cookie from 'cookie';
import moment from 'moment';
import jwt from 'jsonwebtoken';
import { cors } from '../../../lib/cors';
export default async function handler(req, res)
{
await cors(req, res);
if(req.headers.cookie !== undefined)
{
const cookies = cookie.parse(req.headers?.cookie ? req.headers?.cookie : "");
if(cookies.jwt !== undefined && cookies.jwt !== null)
{
var client_jwt_decoded = jwt.verify(cookies.jwt, process.env.JWT_SECRET_CLIENT);
var crm_jwt = jwt.sign(client_jwt_decoded, process.env.JWT_SECRET_CRM, { noTimestamp: true });
try
{
axios.get(`${ process.env.CRM_API_HOST }/lk/GetFile/`, {
params: { ...client_jwt_decoded, id: req.query.id },
responseType: 'arraybuffer',
headers: {
"Authorization": `Bearer ${ crm_jwt }`,
}
})
.then((crm_response) =>
{
res.status(200).send(crm_response.data);
})
.catch((error) =>
{
console.error(error);
res.status(500);
});
}
catch(e)
{
console.error(e);
res.status(500);
}
}
else
{
res.status(403);
}
}
}

View File

@ -0,0 +1,52 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import axios from 'axios';
import { Cookies } from 'react-cookie';
import cookie from 'cookie';
import moment from 'moment';
import jwt from 'jsonwebtoken';
import { cors } from '../../../lib/cors';
export default async function handler(req, res)
{
await cors(req, res);
if(req.headers.cookie !== undefined)
{
const cookies = cookie.parse(req.headers?.cookie ? req.headers?.cookie : "");
if(cookies.jwt !== undefined && cookies.jwt !== null)
{
var client_jwt_decoded = jwt.verify(cookies.jwt, process.env.JWT_SECRET_CLIENT);
var crm_jwt = jwt.sign(client_jwt_decoded, process.env.JWT_SECRET_CRM, { noTimestamp: true });
try
{
axios.get(`${ process.env.CRM_API_HOST }/lk/Contract/GetUPDPrintForm/`, {
params: { ...client_jwt_decoded, contract_number: req.query.contract, num: req.query.num, type: req.query.type, date: req.query.date },
responseType: 'arraybuffer',
headers: {
"Authorization": `Bearer ${ crm_jwt }`,
}
})
.then((crm_response) =>
{
res.status(200).send(crm_response.data);
})
.catch((error) =>
{
console.error(error);
res.status(500);
});
}
catch(e)
{
console.error(e);
res.status(500);
}
}
else
{
res.status(403);
}
}
}

View File

@ -0,0 +1,52 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import axios from 'axios';
import { Cookies } from 'react-cookie';
import cookie from 'cookie';
import moment from 'moment';
import jwt from 'jsonwebtoken';
import { cors } from '../../../lib/cors';
export default async function handler(req, res)
{
await cors(req, res);
if(req.headers.cookie !== undefined)
{
const cookies = cookie.parse(req.headers?.cookie ? req.headers?.cookie : "");
if(cookies.jwt !== undefined && cookies.jwt !== null)
{
var client_jwt_decoded = jwt.verify(cookies.jwt, process.env.JWT_SECRET_CLIENT);
var crm_jwt = jwt.sign(client_jwt_decoded, process.env.JWT_SECRET_CRM, { noTimestamp: true });
try
{
axios.get(`${ process.env.CRM_API_HOST }/lk/Contract/GetAktBU/`, {
params: { ...client_jwt_decoded, contract_number: req.query.contract, dateBegin: req.query.date_from, dateEnd: req.query.date_to, },
responseType: 'arraybuffer',
headers: {
"Authorization": `Bearer ${ crm_jwt }`,
}
})
.then((crm_response) =>
{
res.status(200).send(crm_response.data);
})
.catch((error) =>
{
console.error(error);
res.status(500);
});
}
catch(e)
{
console.error(e);
res.status(500);
}
}
else
{
res.status(403);
}
}
}

View File

@ -4,10 +4,19 @@ import "react-widgets/styles.css";
export default class DateInput extends React.Component
{
render() {
_handle_onChange = (date) =>
{
if(this.props.onChange !== undefined)
{
this.props.onChange(date);
}
}
render()
{
return (
<div className="date_input_wrapper">
<DatePicker placeholder={this.props.placeholder} />
<DatePicker placeholder={ this.props.placeholder } value={ this.props.value } onChange={ this._handle_onChange }/>
</div>
)
}

View File

@ -0,0 +1,50 @@
import React from "react";
import { SpinnerCircular } from 'spinners-react';
import { getFile } from "../../../actions";
export default class DownloadPdfButton extends React.Component
{
constructor(props)
{
super(props);
this.state = {
downloading: false,
};
}
_handle_onDownloadFile = () =>
{
const { id, filename } = this.props;
const { downloading } = this.state;
if(!downloading)
{
this.setState({ downloading: true }, () =>
{
getFile({ id, filename })
.then(() =>
{
this.setState({ downloading: false });
})
.catch(() =>
{
this.setState({ downloading: false });
});
});
}
}
render()
{
const { downloading } = this.state;
return (
<a style={{ cursor: "pointer" }} className="button button-blue" onClick={ () => { this._handle_onDownloadFile() }}>
{ downloading ? (
<SpinnerCircular size={24} thickness={100} speed={100} color="rgba(255, 255, 255, 1)" secondaryColor="rgba(255, 255, 255, 0.5)" />
) : "Скачать" }
</a>
)
}
}

View File

@ -0,0 +1,50 @@
import React from "react";
import { SpinnerCircular } from 'spinners-react';
import { getPrintFile } from "../../../actions";
export default class DownloadPrintFormPdfButton extends React.Component
{
constructor(props)
{
super(props);
this.state = {
downloading: false,
};
}
_handle_onDownloadFile = () =>
{
const { downloading } = this.state;
const { contract, num, date, type, filename } = this.props;
if(!downloading)
{
this.setState({ downloading: true }, () =>
{
getPrintFile({ contract, num, date, type, filename })
.then(() =>
{
this.setState({ downloading: false });
})
.catch(() =>
{
this.setState({ downloading: false });
});
});
}
}
render()
{
const { downloading } = this.state;
return (
<a style={{ cursor: "pointer" }} className="button button-blue" onClick={ () => { this._handle_onDownloadFile() }}>
{ downloading ? (
<SpinnerCircular size={24} thickness={100} speed={100} color="rgba(255, 255, 255, 1)" secondaryColor="rgba(255, 255, 255, 0.5)" />
) : "Скачать" }
</a>
)
}
}

View File

@ -10,13 +10,17 @@ export default class MainHeader extends React.Component
render()
{
const { logo_url } = this.props;
console.log("Header", "this.props", this.props);
return (
<header>
<div className="container">
<a href="/" className="logo">
<img src="/assets/images/logo.svg" alt="" width="217px" height="32px" />
</a>
<Link href={ logo_url !== undefined ? logo_url : "/" }>
<a className="logo">
<img src="/assets/images/logo.svg" alt="" width="217px" height="32px" />
</a>
</Link>
<div className="header_menu">
<nav>
<ul>

View File

@ -37,7 +37,11 @@ class CalendarCellModal extends Component
<div className="modal">
<div className="calendar_payment">
<div className="day">
<span>16</span> июня
{ selected_payment && (
<>
<span>{ moment(selected_payment.date, "YYYY-MM-DD").format("DD") }</span> { moment(selected_payment.date).format("MMM") }
</>
) }
</div>
<div className="payment_table">
<div className="table_row table_header">
@ -52,7 +56,7 @@ class CalendarCellModal extends Component
</Link>
</div>
<div className="table_cell">
<b>{ numeral(payment.total_amount).format('') } р.</b>
<b>{ numeral(payment.total_amount).format(' ., ') } </b>
</div>
</div>
)) }

View File

@ -21,14 +21,14 @@ class NewsCard extends Component
{
return (
<li key={ index } style={ p === page ? { fontWeight: "bold" } : {} }>
<a onClick={ () => p === page ? {} : this.props.onPage(p) }>{ p }</a>
<a style={{ cursor: "pointer" }} onClick={ () => p === page ? {} : this.props.onPage(p) }>{ p }</a>
</li>
)
}
render()
{
const { pages } = this.props;
const { pages, showAll } = this.props;
let page = this.props.page;
if(page < 0) { page = pages; }
@ -116,6 +116,11 @@ class NewsCard extends Component
{ page !== 1 && (<li><a style={{ cursor: "pointer" }} onClick={ () => this.props.onPage(page - 1) }>{`<`}</a></li>) }
{ pagesLinks }
{ page < pages && (<li><a style={{ cursor: "pointer" }} onClick={ () => this.props.onPage(page + 1) }>{`>`}</a></li>) }
{ showAll && (
<li>
<a style={{ cursor: "pointer" }} onClick={ this.props.onAll }>Все</a>
</li>
) }
</ul>
</div>
)

View File

@ -12,8 +12,9 @@ import Header from '../components/Header';
import Footer from '../components/Footer';
import Company from "../components/Company";
import InnerMenu from "./components/InnerMenu";
import DownloadPdfButton from "../components/DownloadPdfButton";
import { getContractInfo, getContractAgreement } from "../../actions";
import { getContractInfo, getContractAgreement, getFile } from "../../actions";
class ContractPage extends React.Component
{
@ -52,9 +53,16 @@ class ContractPage extends React.Component
render()
{
const { contract_date, loading } = this.state;
const { loading, contract_date, agreement, } = this.state;
const { number } = this.props;
const types = {
contracts: "Договор",
redemptions: "Выкупные документы",
agreements: "Дополнительное соглашение",
assignments: "Договор цессии",
};
return (
<React.Fragment>
<Head>
@ -71,55 +79,35 @@ class ContractPage extends React.Component
<div className="container">
<div className="title_wrapper">
<div className="left">
<h1 className="section_title">Договор { number.replace("_", "/") }{ contract_date !== null && (<> от { moment(contract_date).format("DD.MM.YYYY") }</>)}</h1>
<h1 className="section_title">Договор { number }{ contract_date !== null && (<> от { moment(contract_date).format("DD.MM.YYYY") }</>)}</h1>
</div>
<Company/>
</div>
<div className="aside_container about">
<InnerMenu number={ number } { ...this.props }/>
<article>
<div className="dosc_list">
<div className="row">
<p className="doc_name i-pdf">
Договор
<span>Краткое описание. Может быть много-много строк.
Столько строк, сколько есть в описании</span>
</p>
<a href="#" className="button button-blue">Скачать</a>
{ loading ? (
<div className="table_row table_header" style={{ minHeight: 300, display: "flex", justifyContent: "center", alignItems: "center" }}>
<SpinnerCircular size={90} thickness={51} speed={100} color="rgba(28, 1, 169, 1)" secondaryColor="rgba(236, 239, 244, 1)" />
</div>
<div className="row">
<p className="doc_name i-pdf">
Договор цессии
<span>Краткое описание. Может быть много-много строк.
Столько строк, сколько есть в описании</span>
</p>
<a href="#" className="button button-blue">Скачать</a>
) : (
<div className="dosc_list">
{ agreement !== undefined && agreement !== null && agreement.map((document, index) => (
<React.Fragment key={ index }>
{ document.documents !== undefined && document.documents !== null && document.documents.map((file, file_index) => (
<div className="row" key={ file_index }>
<p className="doc_name i-pdf">
{ types[document.type] }
<span style={{ width: "100%"}}>{ file.number } от { file.date }</span>
{ file.type !== undefined && <span>{ file.type }</span> }
</p>
<DownloadPdfButton id={ file.url } filename={ `${ file.url }.pdf` }/>
</div>
)) }
</React.Fragment>
)) }
</div>
<div className="row">
<p className="doc_name i-pdf">
Дополнительное соглашение 1
<span>Краткое описание. Может быть много-много строк.
Столько строк, сколько есть в описании</span>
</p>
<a href="#" className="button button-blue">Скачать</a>
</div>
<div className="row">
<p className="doc_name i-pdf">
Дополнительное соглашение 2
<span>Краткое описание. Может быть много-много строк.
Столько строк, сколько есть в описании</span>
</p>
<a href="#" className="button button-blue">Скачать</a>
</div>
<div className="row">
<p className="doc_name i-pdf">
Выкупные документы
<span>Краткое описание. Может быть много-много строк.
Столько строк, сколько есть в описании</span>
</p>
<a href="#" className="button button-blue">Скачать</a>
</div>
</div>
) }
</article>
</div>
</div>
@ -134,8 +122,6 @@ class ContractPage extends React.Component
function mapStateToProps(state, ownProps)
{
return {
company: state.company,
schedule: state.payments,
contract_date: state.contract.date,
agreement: state.contract.agreement,
}

View File

@ -12,8 +12,10 @@ import Header from '../components/Header';
import Footer from '../components/Footer';
import InnerMenu from "./components/InnerMenu";
import Company from "../components/Company";
import DateInput from '../components/DatePicker';
import DownloadPrintFormPdfButton from "../components/DownloadPrintFormPdfButton";
import { getContractInfo, getContractDocuments } from "../../actions";
import { getContractInfo, getContractDocuments, getReconciliationFile } from "../../actions";
class ContractDocumentsPage extends React.Component
{
@ -21,9 +23,13 @@ class ContractDocumentsPage extends React.Component
{
super(props);
this.state = {
opened: [],
contract_date: null,
documents: null,
loading: false,
period_date_start: null,
period_date_end: null,
reconciliation_requested: false,
}
}
@ -39,7 +45,7 @@ class ContractDocumentsPage extends React.Component
{
if(!this.state.loading && this.props.number !== undefined)
{
this.setState({ loading: true }, () =>
this.setState({ loading: true, period_date_end: moment().toDate() }, () =>
{
getContractInfo({ dispatch: this.props.dispatch, number: this.props.number });
@ -50,11 +56,70 @@ class ContractDocumentsPage extends React.Component
}
}
componentDidUpdate(prevProps, prevState)
{
if(this.state.period_date_start === null)
{
if(prevState.contract_date === null && this.state.contract_date !== null)
{
this.setState({ period_date_start: moment(this.state.contract_date).toDate() });
}
}
}
_handle_onReconciliationFileRequest = () =>
{
const { number } = this.props;
const { reconciliation_requested, period_date_start, period_date_end, } = this.state;
if(!reconciliation_requested)
{
this.setState({ reconciliation_requested: true }, () =>
{
const date_from = moment(period_date_start).format("YYYY-MM-DD");
const date_to = moment(period_date_end).format("YYYY-MM-DD");
getReconciliationFile({
contract: number,
date_from: date_from,
date_to: date_to,
filename: `${ number }_reconciliation_${ date_from }_${ date_to }.pdf`,
})
.then(() =>
{
this.setState({ reconciliation_requested: false });
})
.catch(() =>
{
this.setState({ reconciliation_requested: false });
});
});
}
}
_handle_onPeriodDate_start = (date) =>
{
this.setState({ period_date_start: date });
}
_handle_onPeriodDate_end = (date) =>
{
this.setState({ period_date_end: date });
}
render()
{
const { contract_date, loading } = this.state;
const { loading, contract_date, documents, period_date_start, period_date_end, reconciliation_requested } = this.state;
const { number } = this.props;
console.log("documentsdocumentsdocumentsdocumentsdocuments");
console.log(documents);
const types = {
upd: "УПД по очередным платежам",
upd_avans: "УПД по авансовым платежам",
};
return (
<React.Fragment>
<Head>
@ -71,85 +136,67 @@ class ContractDocumentsPage extends React.Component
<div className="container">
<div className="title_wrapper">
<div className="left">
<h1 className="section_title">Договор { number.replace("_", "/") }{ contract_date !== null && (<> от { moment(contract_date).format("DD.MM.YYYY") }</>)}</h1>
<h1 className="section_title">Договор { number }{ contract_date !== null && (<> от { moment(contract_date).format("DD.MM.YYYY") }</>)}</h1>
</div>
<Company />
</div>
<div className="aside_container about">
<InnerMenu number={ number } {...this.props} />
<article>
<div className="reconciliation_form">
<p>Акт сверки</p>
<div className="form_group">
<div className="form_field">
<input type="text" className="date_input" value="" placeholder="Дата начала договора" onFocus={() => {/*(this.type='date')*/ }} onBlur={() => {/*(this.value == '' ? this.type='text' : this.type='date')*/ }} />
</div>
<div className="form_field">
<input type="text" className="date_input" value="" placeholder="Дата окончания договора" onFocus={() => { /*(this.type='date')*/ }} onBlur={() => {/*(this.value == '' ? this.type='text' : this.type='date')*/ }} />
</div>
</div>
<div className="form_group">
<button className="button button-blue">Скачать</button>
{/*<button className="button button-blue">Отправить в ЭДО</button>*/}
</div>
</div>
{ loading ? (
<div className="table_row table_header" style={{ minHeight: 300, display: "flex", justifyContent: "center", alignItems: "center" }}>
<SpinnerCircular size={90} thickness={51} speed={100} color="rgba(28, 1, 169, 1)" secondaryColor="rgba(236, 239, 244, 1)" />
</div>
) : (
<div className="dropdown_blocks_list">
<div className="dropdown_block bt">
<div className="block_header">
<p>
УПД по очередным платежам
</p>
<button className="block_toggle"></button>
</div>
<div className="block_body">
<div className="transaction_detail">
<p> постановления: <b>3432434242334</b></p>
<ul>
<li>Сумма: <b>3 000,00 р.</b></li>
<li>Дата: <b>01/01/2020</b></li>
<li>Статус: <b className="success">Оплачен</b></li>
<li>Штраф: п. 1.15 - Несоблюдение правил парковки </li>
</ul>
<>
<div className="reconciliation_form">
<p>Акт сверки</p>
<div className="form_group">
<div className="form_field">
<DateInput placeholder="Дата начала периода" value={ period_date_start } onChange={ this._handle_onPeriodDate_start }/>
</div>
<div className="form_field">
<DateInput placeholder="Дата окончания периода" value={ period_date_end } onChange={ this._handle_onPeriodDate_end }/>
</div>
</div>
</div>
<div className="dosc_list medium-icon">
<div className="row">
<p className="doc_name i-pdf i-medium">
Дополнительное соглашение 1
</p>
<a href="#" className="button button-blue download-icon">Скачать</a>
</div>
<div className="row">
<p className="doc_name i-pdf i-medium">
Дополнительное соглашение 2
</p>
<a href="#" className="button button-blue download-icon">Скачать</a>
</div>
<div className="row">
<p className="doc_name i-pdf i-medium">
Выкупные документы
</p>
<a href="#" className="button button-blue download-icon">Скачать</a>
<div className="form_group">
<button className="button button-blue" onClick={ () => { this._handle_onReconciliationFileRequest() }}>
<>
{ reconciliation_requested ? (
<SpinnerCircular size={24} thickness={100} speed={100} color="rgba(255, 255, 255, 1)" secondaryColor="rgba(255, 255, 255, 0.5)" />
) : "Скачать" }
</>
</button>
{/*<button className="button button-blue">Отправить в ЭДО</button>*/}
</div>
</div>
<div className="dropdown_block bt">
<div className="block_header">
<p>
УПД по доп.услугам
</p>
<button className="block_toggle"></button>
</div>
<div className="block_body"></div>
<div className="dropdown_blocks_list">
{ documents !== undefined && documents !== null ? (
<>
{ documents.upd && documents.upd.map((doc, index) => (
<React.Fragment key={ index }>
<div className="dropdown_block bt">
<div className="block_header">
<p>{ types[ doc.type.toLowerCase() ] }</p>
<button className="block_toggle"></button>
</div>
</div>
<div className="dosc_list medium-icon">
{ doc.upd.map((upd_document, upd_document_index) => (
<div className="row" key={ upd_document_index }>
<p className="doc_name i-pdf i-medium">
{ upd_document.num } от { moment(upd_document.date).format("DD.MM.YYYY") }
</p>
<DownloadPrintFormPdfButton filename={ `${ number }_${ upd_document.type }_${ upd_document.num }.pdf` } contract={ number } num={ upd_document.num } date={ upd_document.date } type={ upd_document.type }/>
</div>
)) }
</div>
</React.Fragment>
)) }
</>
) : null }
</div>
</div>
</>
) }
</article>
</div>
@ -165,8 +212,6 @@ class ContractDocumentsPage extends React.Component
function mapStateToProps(state, ownProps)
{
return {
company: state.company,
schedule: state.payments,
contract_date: state.contract.date,
documents: state.contract.documents,
}
@ -184,3 +229,17 @@ export const getServerSideProps = reduxWrapper.getServerSideProps(store =>
);
export default withRouter(connect(mapStateToProps)(ContractDocumentsPage));
{/*}
<div className="block_body">
<div className="transaction_detail">
<p> постановления: <b>3432434242334</b></p>
<ul>
<li>Сумма: <b>3 000,00 р.</b></li>
<li>Дата: <b>01/01/2020</b></li>
<li>Статус: <b className="success">Оплачен</b></li>
<li>Штраф: п. 1.15 - Несоблюдение правил парковки </li>
</ul>
</div>
</div>
{*/}

View File

@ -3,6 +3,8 @@ import Head from 'next/head';
import Image from 'next/image';
import { connect } from "react-redux";
import { withRouter } from 'next/router';
import numeral from "numeral";
import moment from "moment";
import { SpinnerCircular } from 'spinners-react';
import { reduxWrapper } from '../../store';
@ -13,8 +15,6 @@ import Company from "../components/Company";
import InnerMenu from "./components/InnerMenu";
import { getContract, getContractInfo } from './../../actions';
import numeral from "numeral";
import moment from "moment";
class ContractSchedulePage extends React.Component
{
@ -40,13 +40,8 @@ class ContractSchedulePage extends React.Component
componentDidMount()
{
console.log("this.props");
console.log(this.props);
if(!this.state.loading && this.props.number !== undefined)
{
console.log("this.props.number", this.props.number);
this.setState({ loading: true }, () =>
{
getContractInfo({ dispatch: this.props.dispatch, number: this.props.number });
@ -107,7 +102,7 @@ class ContractSchedulePage extends React.Component
<div className="container">
<div className="title_wrapper">
<div className="left">
<h1 className="section_title">Договор { number.replace("_", "/") }{ contract_date !== null && (<> от { moment(contract_date).format("DD.MM.YYYY") }</>)}</h1>
<h1 className="section_title">Договор { number }{ contract_date !== null && (<> от { moment(contract_date).format("DD.MM.YYYY") }</>)}</h1>
</div>
<Company/>
</div>
@ -118,8 +113,8 @@ class ContractSchedulePage extends React.Component
<div className="table_row table_header">
<div className="table_cell"> платежа</div>
<div className="table_cell">Дата лизингового платежа</div>
<div className="table_cell">Лизинговый платеж с НДС (рубли)</div>
<div className="table_cell">НДС, 20% (рубли)</div>
<div className="table_cell">Лизинговый платеж с НДС</div>
<div className="table_cell">НДС, 20%</div>
<div className="table_cell">Статус платежа</div>
<div className="table_cell">Платежное поручение</div>
</div>
@ -141,21 +136,21 @@ class ContractSchedulePage extends React.Component
<div className={ `table_row ${ opened.indexOf(payment.number) > -1 ? "opened" : "" }` } data-status={ payment.status === "NotPaid" && pd < today ? "notpaid" : statuses[payment.status] } key={ index }>
<div className="table_cell" data-title="Платеж №">{ payment.number }</div>
<div className="table_cell" data-title="от">{ moment(payment.date, "DD-MM-YYYY").format("DD.MM.YYYY") }</div>
<div className="table_cell" data-title="На сумму">{ numeral(payment.total_amount).format('') }</div>
<div className="table_cell" data-title="НДС, 20%">{ numeral(payment.vat_amount).format('') }</div>
<div className="table_cell" data-title="На сумму">{ numeral(payment.total_amount).format(' ., ') } </div>
<div className="table_cell" data-title="НДС, 20%">{ numeral(payment.vat_amount).format(' ., ') } </div>
<div className="table_cell">
{ payment.status === "Paid" && "Оплачено" }
{ payment.status === "NotPaid" && "Не оплачено" }
{ payment.status === "HalfPaid" && "Частично оплачено" }
{ payment.status === "OverPaid" && (
<div className="table_cell"><span>Переплата</span> <span>{ numeral(payment.total_amount).format('') } </span></div>
) }
{ payment.status === "Paid" && "Оплачено" }
{ payment.status === "NotPaid" && "Не оплачено" }
{ payment.status === "HalfPaid" && "Частично оплачено" }
{ payment.status === "OverPaid" && (
<div className="table_cell"><span>Переплата</span> <span>{ numeral(payment.total_amount).format(' ., ') } </span></div>
) }
</div>
<div className="table_cell">
{ payment.invoices.map((invoice, invoice_index) =>
(
<React.Fragment key={invoice_index}>
<p style={{ paddingBottom: "15px", lineHeight: "18px" }}>{ invoice.number } от { moment(invoice.date, "DD-MM-YYYY").format("DD.MM.YYYY") } на сумму { numeral(invoice.total_amount).format('') } </p>
<p style={{ paddingBottom: "15px", lineHeight: "18px" }}>{ invoice.number } от { moment(invoice.date, "DD-MM-YYYY").format("DD.MM.YYYY") } на сумму { numeral(invoice.total_amount).format(' ., ') } </p>
</React.Fragment>
)) }
</div>

View File

@ -3,6 +3,7 @@ import Head from 'next/head';
import Image from 'next/image';
import { connect } from "react-redux";
import { withRouter } from 'next/router';
import numeral from "numeral";
import moment from "moment";
import { SpinnerCircular } from 'spinners-react';
@ -24,6 +25,10 @@ class ContractServicesPage extends React.Component
opened: [],
contract_date: null,
loading: false,
helpcard: null,
insurance: null,
registration: null,
telematic: null,
};
}
@ -31,6 +36,10 @@ class ContractServicesPage extends React.Component
{
return {
contract_date: nextProps.contract_date,
helpcard: nextProps.helpcard,
insurance: nextProps.insurance,
registration: nextProps.registration,
telematic: nextProps.telematic,
};
}
@ -71,7 +80,7 @@ class ContractServicesPage extends React.Component
render()
{
const { opened, contract_date, loading } = this.state;
const { opened, loading, contract_date, helpcard, insurance, registration, telematic, } = this.state;
const { number } = this.props;
return (
@ -90,92 +99,156 @@ class ContractServicesPage extends React.Component
<div className="container">
<div className="title_wrapper">
<div className="left">
<h1 className="section_title">Договор { number.replace("_", "/") }{ contract_date !== null && (<> от { moment(contract_date).format("DD.MM.YYYY") }</>)}</h1>
<h1 className="section_title">Договор { number }{ contract_date !== null && (<> от { moment(contract_date).format("DD.MM.YYYY") }</>)}</h1>
</div>
<Company/>
</div>
<div className="aside_container about">
<InnerMenu number={ number } { ...this.props }/>
<article>
<div className="dropdown_blocks_list filled zero-margin">
{ loading ? (
<div className="table_row table_header" style={{ minHeight: 300, display: "flex", justifyContent: "center", alignItems: "center" }}>
<SpinnerCircular size={90} thickness={51} speed={100} color="rgba(28, 1, 169, 1)" secondaryColor="rgba(236, 239, 244, 1)" />
</div>
) : (
<div className="dropdown_blocks_list filled zero-margin">
<div className={`dropdown_block ${ opened.indexOf("ratcard") > -1 ? 'open' : '' }`}>
<div className="block_header" onClick={ () => this._handle_onCard('ratcard') }>
<p className="with-icon">
<img src="/assets/images/lk/additional-1.svg" alt="Карта РАТ" width="32px" height="32px" />
Карта РАТ
</p>
<button className="block_toggle"></button>
</div>
<div className="block_body">
<div className="company">
<ul>
<li>Номер карты: <b>34234324324324</b></li>
<li>Сайт: <b>www.sog.ru</b></li>
</ul>
<div className={`dropdown_block ${ opened.indexOf("ratcard") > -1 ? 'open' : '' }`}>
<div className="block_header" onClick={ () => this._handle_onCard('ratcard') }>
<p className="with-icon">
<img src="/assets/images/lk/additional-1.svg" alt="Карта РАТ" width="32px" height="32px" />
Карта РАТ
</p>
<button className="block_toggle"></button>
</div>
<p>Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент</p>
{ helpcard !== undefined && helpcard !== null && helpcard.length > 0 ? (
helpcard.map((entry, index) => (
<React.Fragment key={ index }>
{ entry.card_number !== null ? (
<div className="block_body">
<div className="company">
<ul>
<li>Номер карты: <b>{ entry.card_number }</b></li>
<li>Тип карты: <b>{ entry.card_type }</b></li>
<li>Действует до: <b>{ moment(entry.date).format("DD.MM.YYYY") }</b></li>
</ul>
</div>
<>
{ entry && entry.description && (
<p dangerouslySetInnerHTML={{ __html: entry.description.replace(/;/g, ";<br/>") }}/>
) }
</>
</div>
) : (
<div className="block_body"><p>Нет данных</p></div>
) }
</React.Fragment>
))
) : (
<div className="block_body"><p>Нет данных</p></div>
) }
</div>
</div>
<div className={`dropdown_block ${ opened.indexOf("insurance") > -1 ? 'open' : '' }`}>
<div className="block_header" onClick={ () => this._handle_onCard('insurance') }>
<p className="with-icon">
<img src="/assets/images/lk/additional-2.svg" alt="Страхование" width="32px" height="32px" />
Страхование
</p>
<button className="block_toggle"></button>
</div>
<div className="block_body">
<div className="company">
<p className="title">Каско</p>
<ul>
<li>Страховая компания: <b>Согласие</b></li>
<li>Сайт: <b>www.sog.ru</b></li>
<li>Телефон: <b>+74951112233</b></li>
<li>Номер полиса: <b>34234324324324</b></li>
<li>Период действия: <b>01/01/2020 - 01/01/2025</b></li>
<li>Страховая сумма: <b>3 400 000,00 р.</b></li>
</ul>
<div className={`dropdown_block ${ opened.indexOf("insurance") > -1 ? 'open' : '' }`}>
<div className="block_header" onClick={ () => this._handle_onCard('insurance') }>
<p className="with-icon">
<img src="/assets/images/lk/additional-2.svg" alt="Страхование" width="32px" height="32px" />
Страхование
</p>
<button className="block_toggle"></button>
</div>
<p>Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент</p>
</div>
</div>
<div className={`dropdown_block ${ opened.indexOf("registration") > -1 ? 'open' : '' }`}>
<div className="block_header" onClick={ () => this._handle_onCard('registration') }>
<p className="with-icon">
<img src="/assets/images/lk/additional-3.svg" alt="Регистрация" width="32px" height="32px" />
Регистрация
</p>
<button className="block_toggle"></button>
</div>
<div className="block_body">
<p>Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент</p>
</div>
</div>
<div className={`dropdown_block ${ opened.indexOf("telematic") > -1 ? 'open' : '' }`}>
<div className="block_header" onClick={ () => this._handle_onCard('telematic') }>
<p className="with-icon">
<img src="/assets/images/lk/additional-4.svg" alt="Телематика" width="32px" height="32px" />
Телематика
</p>
<button className="block_toggle"></button>
</div>
<div className="block_body">
<div className="company">
<ul>
<li>Сайт: <b>www.telematic.ru</b></li>
<li>Логин: <b>test</b></li>
<li>Пароль: <b>test</b></li>
</ul>
<div className="block_body">
{ insurance !== undefined && insurance !== null ? (
<>
{ insurance.kasko !== undefined && insurance.kasko !== null && insurance.kasko.map((entry, index) => (
<React.Fragment key={ index }>
<div className="company">
<p className="title">КАСКО</p>
<ul>
{ entry.company && (<li>Страховая компания: <b>{ entry.company }</b></li>) }
{ entry.site && (<li>Сайт: <b>{ entry.site }</b></li>) }
{ entry.phone && (<li>Телефон: <b>{ entry.phone }</b></li>) }
{ entry.number && (<li>Номер полиса: <b>{ entry.number }</b></li>) }
{ entry.period && (<li>Период действия: <b>{ entry.period }</b></li>) }
{ entry.amount && (<li>Страховая сумма: <b>{ numeral(entry.amount).format(' ., ') } </b></li>) }
</ul>
</div>
{ entry.description && (<p>{ entry.description }</p>) }
</React.Fragment>
)) }
{ insurance.osago !== undefined && insurance.osago !== null && insurance.osago.map((entry, index) => (
<React.Fragment key={ index }>
<div className="company">
<p className="title">ОСАГО</p>
<ul>
{ entry.company && (<li>Страховая компания: <b>{ entry.company }</b></li>) }
{ entry.site && (<li>Сайт: <b>{ entry.site }</b></li>) }
{ entry.phone && (<li>Телефон: <b>{ entry.phone }</b></li>) }
{ entry.number && (<li>Номер полиса: <b>{ entry.number }</b></li>) }
{ entry.period && (<li>Период действия: <b>{ entry.period }</b></li>) }
{ entry.amount && (<li>Страховая сумма: <b>{ numeral(entry.amount).format(' ., ') } </b></li>) }
</ul>
</div>
{ entry.description && (<p>{ entry.description }</p>) }
</React.Fragment>
)) }
{ insurance.nsib !== undefined && insurance.nsib !== null && insurance.nsib.map((entry, index) => (
<React.Fragment key={ index }>
<div className="company">
<p className="title">НСИБ</p>
<ul>
{ entry.company && (<li>Страховая компания: <b>{ entry.company }</b></li>) }
{ entry.site && (<li>Сайт: <b>{ entry.site }</b></li>) }
{ entry.phone && (<li>Телефон: <b>{ entry.phone }</b></li>) }
{ entry.number && (<li>Номер полиса: <b>{ entry.number }</b></li>) }
{ entry.period && (<li>Период действия: <b>{ entry.period }</b></li>) }
{ entry.amount && (<li>Страховая сумма: <b>{ numeral(entry.amount).format(' ., ') } </b></li>) }
</ul>
</div>
{ entry.description && (<p>{ entry.description }</p>) }
</React.Fragment>
)) }
</>
) : (
<div className="block_body"><p>Нет данных</p></div>
) }
</div>
<p>Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент</p>
</div>
</div>
<div className={`dropdown_block ${ opened.indexOf("registration") > -1 ? 'open' : '' }`}>
<div className="block_header" onClick={ () => this._handle_onCard('registration') }>
<p className="with-icon">
<img src="/assets/images/lk/additional-3.svg" alt="Регистрация" width="32px" height="32px" />
Регистрация
</p>
<button className="block_toggle"></button>
</div>
<div className="block_body"><p>Нет данных</p></div>
</div>
<div className={`dropdown_block ${ opened.indexOf("telematic") > -1 ? 'open' : '' }`}>
<div className="block_header" onClick={ () => this._handle_onCard('telematic') }>
<p className="with-icon">
<img src="/assets/images/lk/additional-4.svg" alt="Телематика" width="32px" height="32px" />
Телематика
</p>
<button className="block_toggle"></button>
</div>
<div className="block_body"><p>Нет данных</p></div>
{/*}
<div className="block_body">
<div className="company">
<ul>
<li>Сайт: <b>www.telematic.ru</b></li>
<li>Логин: <b>test</b></li>
<li>Пароль: <b>test</b></li>
</ul>
</div>
<p>Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент Текстовый контент</p>
</div>
{*/}
</div>
</div>
</div>
) }
</article>
</div>
</div>
@ -190,9 +263,11 @@ class ContractServicesPage extends React.Component
function mapStateToProps(state, ownProps)
{
return {
company: state.company,
schedule: state.payments,
contract_date: state.contract.date,
helpcard: state.contract.helpcard,
insurance: state.contract.insurance,
registration: state.contract.registration,
telematic: state.contract.telematic,
}
}

View File

@ -202,17 +202,27 @@ class CalendarPage extends React.Component
return (
<div className={index == 0 ? "grid_week active" : "grid_week"} key={"week_" + index}>
{ week.map((day, index) => {
if(day.payment)
{
return (
<div key={ index } style={{ cursor: "pointer" }} className={`grid_cell payment ${ day.date.month() !== month ? 'disabled' : '' } ${ day.date.format("YYYYMMDD") === moment().format("YYYYMMDD") ? 'current' : '' } `} onClick={ () => this._handle_onDayClick(day) }>
<div className="cell_header">
<p><span>{ day.date.format("DD") }</span> { day.date.format("MMM").toLocaleLowerCase() } { day.date.format("Y").toLocaleLowerCase() }</p>
</div>
<div className="cell_body">{ day.payment && (
<p>
Общий платеж
<span>{ numeral(day.payment.total).format(' ., ') } </span>
</p>
)}
</div>
</div>
)
}
return (
<div key={ index } className={`grid_cell ${ day.date.month() !== month ? 'disabled' : '' } ${ day.date.format("YYYYMMDD") === moment().format("YYYYMMDD") ? 'current' : '' } `}>
<div className="cell_header">
<p><span>{ day.date.format("DD") }</span> { day.date.format("MMM").toLocaleLowerCase() } { day.date.format("Y").toLocaleLowerCase() }</p>
</div>
<div className="cell_body">{ day.payment && (
<p onClick={ () => this._handle_onDayClick(day) }>
Общий платеж
<span>{ numeral(day.payment.total).format('') } р.</span>
</p>
)}
<p><span>{ day.date.format("DD") }</span> { day.date.format("MMM").toLocaleLowerCase() } { day.date.format("Y").toLocaleLowerCase() }</p>
</div>
</div>
)
@ -220,109 +230,6 @@ class CalendarPage extends React.Component
</div>
)
}) }
{/*}
<div className="grid_cell disabled">
<div className="cell_header">
<p><span>30</span> мая</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell disabled">
<div className="cell_header">
<p><span>31</span> мая</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p><span>01</span> июня</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p><span>02</span> июня</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell current">
<div className="cell_header">
<p><span>03</span> июня</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p><span>04</span> июня</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p><span>05</span> июня</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p><span>30</span> мая</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p><span>31</span> мая</p>
</div>
<div className="cell_body">
<p>
Общий платеж
<span>239 400,00 р.</span>
</p>
</div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p><span>01</span> июня</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p><span>02</span> июня</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p><span>03</span> июня</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p><span>04</span> июня</p>
</div>
<div className="cell_body"></div>
</div>
<div className="grid_cell">
<div className="cell_header">
<p><span>05</span> июня</p>
</div>
<div className="cell_body"></div>
</div>
{*/}
</div>
</div>
</div>

View File

@ -1,8 +1,12 @@
import React from "react";
import Head from 'next/head';
import Link from "next/link";
import Image from 'next/image';
import { connect } from "react-redux";
import { withRouter } from 'next/router';
import { SpinnerCircular } from 'spinners-react';
import moment from "moment";
import { reduxWrapper } from '../../store';
import Header from '../components/Header';
@ -10,15 +14,68 @@ import Footer from '../components/Footer';
import InnerMenu from "./components/InnerMenu";
import Company from "../components/Company";
import { getContractsList } from '../../actions';
class FinalsPage extends React.Component
{
constructor(props)
{
super(props);
this.state = {
loading: false,
contracts: null,
search: "",
}
}
static getDerivedStateFromProps(nextProps, prevState)
{
return {
contracts: nextProps.contracts,
};
}
componentDidMount()
{
this.setState({ loading: true }, () =>
{
getContractsList({ dispatch: this.props.dispatch, all: true }).then(() => {
this.setState({ loading: false });
}).catch(() => {});
});
}
_handle_onChange_search = (value) =>
{
if(this.state.value !== "" && value === "")
{
this.setState({ search: value }, () => {
this._handle_onSearch();
});
}
else
{
this.setState({ search: value });
}
}
_handle_onSearch = () =>
{
const { search, } = this.state;
this.setState({ loading: true, }, () =>
{
getContractsList({ dispatch: this.props.dispatch, search, all: true}).then(() => {
this.setState({ loading: false });
}).catch(() => {});
});
}
render()
{
const { loading, search, contracts, } = this.state;
return (
<React.Fragment>
<Head>
@ -43,50 +100,37 @@ class FinalsPage extends React.Component
<InnerMenu { ...this.props }/>
<article>
<div className="contract_search">
<form>
<form onSubmit={ (event) => { event.preventDefault(); } }>
<div className="form_field single">
<input type="search" value="" placeholder="Поиск по номеру договора, марке и модели транспорта, VIN и госномеру ТС"/>
<input type="search" value={ search } placeholder="Поиск по номеру договора, марке и модели транспорта, VIN и госномеру ТС" onChange={ (event) => {
this._handle_onChange_search(event.target.value);
} }/>
</div>
<button className="button" disabled="">Поиск</button>
<button className="button" disabled={ search !== "" ? false : true } onClick={ this._handle_onSearch }>Поиск</button>
</form>
</div>
<div className="dosc_list">
<div className="row">
<p className="doc_name i-doc full">
<a href="#">Договор</a>
<span>Краткое описание. Может быть много-много строк.
Столько строк, сколько есть в описании</span>
</p>
{ loading ? (
<div className="table_row table_header" style={{ minHeight: 300, display: "flex", justifyContent: "center", alignItems: "center" }}>
<SpinnerCircular size={90} thickness={51} speed={100} color="rgba(28, 1, 169, 1)" secondaryColor="rgba(236, 239, 244, 1)" />
</div>
<div className="row">
<p className="doc_name i-doc full">
Договор цессии
<span>Краткое описание. Может быть много-много строк.
Столько строк, сколько есть в описании</span>
</p>
) : (
<div className="dosc_list">
{ contracts !== undefined && contracts !== null && (
<>
{ contracts.length > 0 ? contracts.map((contract, index) => (
<div className="row" key={ index }>
<p className="doc_name i-doc full">
<Link href={ `/contract/${ contract.number }/documents` }><a>Договор { contract.number } от { moment(contract.date).format("DD.MM.YYYY") }</a></Link>
<span>{ contract.car.brand.name } { contract.car.model.name } | { contract.car.reg_number !== undefined && contract.car.reg_number !== null ? contract.car.reg_number : "без рег. номера" } | { contract.car.vin_number }</span>
</p>
</div>
)) : (
<p>Нет договоров для отображения</p>
) }
</>
) }
</div>
<div className="row">
<p className="doc_name i-doc full">
Дополнительное соглашение 1
<span>Краткое описание. Может быть много-много строк.
Столько строк, сколько есть в описании</span>
</p>
</div>
<div className="row">
<p className="doc_name i-doc full">
Дополнительное соглашение 2
<span>Краткое описание. Может быть много-много строк.
Столько строк, сколько есть в описании</span>
</p>
</div>
<div className="row">
<p className="doc_name i-doc full">
Выкупные документы
<span>Краткое описание. Может быть много-много строк.
Столько строк, сколько есть в описании</span>
</p>
</div>
</div>
) }
</article>
</div>
</div>
@ -101,7 +145,7 @@ class FinalsPage extends React.Component
function mapStateToProps(state, ownProps)
{
return {
schedule: state.payments,
contracts: state.contracts.list,
}
}

View File

@ -3,22 +3,87 @@ import Head from 'next/head';
import Image from 'next/image';
import { connect } from "react-redux";
import { withRouter } from 'next/router';
import { SpinnerCircular } from 'spinners-react';
import moment from "moment";
import { reduxWrapper } from '../../store';
import Header from '../components/Header';
import Footer from '../components/Footer';
import InnerMenu from "./components/InnerMenu";
import Company from "../components/Company";
import DateInput from '../components/DatePicker';
import { getContractsList } from '../../actions';
class ReconciliationsPage extends React.Component
{
constructor(props)
{
super(props);
this.state = {
loading: false,
contracts: null,
checked: [],
checked_all: true,
}
}
static getDerivedStateFromProps(nextProps, prevState)
{
return {
contracts: nextProps.contracts,
};
}
componentDidMount()
{
this.setState({ loading: true }, () =>
{
getContractsList({ dispatch: this.props.dispatch, all: true }).then(() => {
this.setState({ loading: false });
}).catch(() => {});
});
}
_handle_onAllContracts = () =>
{
this.setState({ checked_all: this.state.checked_all ? false : true, checked: this.state.checked ? [] : this.state.checked });
}
_handle_onContract = (number) =>
{
const { checked_all, contracts } = this.state;
const checked = [ ...this.state.checked ];
if(checked_all)
{
for(let i in contracts)
{
if(contracts[i].number !== number)
{
checked.push(contracts[i].number);
}
}
this.setState({ checked_all: false, checked: checked });
}
else
{
if(checked.indexOf(number) < 0)
{ checked.push(number); }
else
{ checked.splice(checked.indexOf(number), 1); }
this.setState({ checked: checked });
}
}
render()
{
const { loading, contracts, checked, checked_all, } = this.state;
return (
<React.Fragment>
<Head>
@ -44,31 +109,35 @@ class ReconciliationsPage extends React.Component
<article>
<div className="acts_wrapper">
<div className="dosc_list acts_list-checkbox">
<div className="row">
<p className="doc_name">
<input type="checkbox" name="name" id="name" />
<label htmlFor="name">Все договоры</label>
</p>
</div>
<div className="row">
<p className="doc_name i-pdf">
<input type="checkbox" name="name" id="name" />
<label htmlFor="name">1234567 от 21.01.2021</label>
</p>
</div>
<div className="row">
<p className="doc_name i-pdf">
<input type="checkbox" name="name" id="name" />
<label htmlFor="name">1234567 от 21.01.2021</label>
</p>
</div>
{ loading ? (
<div className="table_row table_header" style={{ minHeight: 300, display: "flex", justifyContent: "center", alignItems: "center" }}>
<SpinnerCircular size={90} thickness={51} speed={100} color="rgba(28, 1, 169, 1)" secondaryColor="rgba(236, 239, 244, 1)" />
</div>
) : (
<>
<div className="row">
<p className="doc_name">
<input type="checkbox" name="all" id="all" checked={ checked_all } onChange={ this._handle_onAllContracts } />
<label htmlFor="all">Все договоры</label>
</p>
</div>
{ contracts !== undefined && contracts !== null && contracts.map((contract, index) => (
<div className="row" key={ index }>
<p className="doc_name i-pdf">
<input type="checkbox" checked={ checked_all || checked.indexOf(contract.number) > -1 } name={ `contract_${ contract.number }` } id={ `contract_${ contract.number }` } onChange={ () => this._handle_onContract(contract.number) }/>
<label htmlFor={ `contract_${ contract.number }` }>{ contract.number } от { moment(contract.date).format("DD.MM.YYYY") }</label>
</p>
</div>
)) }
</>
) }
</div>
<div className="reconciliation_form small">
<div className="form_field">
<input type="text" className="date_input" value="" placeholder="Дата начала договора" onFocus={ () => {/*(this.type='date')*/} } onBlur={ () => {/*(this.value == '' ? this.type='text' : this.type='date')*/} } />
<DateInput placeholder="Дата начала периода" />
</div>
<div className="form_field">
<input type="text" className="date_input" value="" placeholder="Дата окончания договора" onFocus={ () => { /*(this.type='date')*/} } onBlur={ () => {/*(this.value == '' ? this.type='text' : this.type='date')*/} } />
<DateInput placeholder="Дата окончания периода" />
</div>
<button className="button button-blue">Скачать</button>
{/*<button className="button button-blue">Отправить в ЭДО</button>*/}
@ -88,8 +157,7 @@ class ReconciliationsPage extends React.Component
function mapStateToProps(state, ownProps)
{
return {
company: state.company,
schedule: state.payments,
contracts: state.contracts.list,
}
}

View File

@ -24,6 +24,7 @@ class IndexPage extends React.Component
super(props);
this.state = {
contracts: null,
order: "number",
sort_number: "desc",
sort_date: "desc",
sort_status: "desc",
@ -35,13 +36,13 @@ class IndexPage extends React.Component
loading: false,
page: 1,
pages: 1,
all: false,
};
}
static getDerivedStateFromProps(nextProps, prevState)
{
return {
company: nextProps.company,
contracts: nextProps.contracts,
page: nextProps.page,
pages: nextProps.pages,
@ -75,9 +76,9 @@ class IndexPage extends React.Component
_handle_onChangeSort_number = () =>
{
this.setState({ loading: true, sort_number: this.state.sort_number === "desc" ? "asc" : "desc" }, () =>
this.setState({ loading: true, order: "number", sort_number: this.state.sort_number === "desc" ? "asc" : "desc" }, () =>
{
getContractsList({ dispatch: this.props.dispatch, order: "number", sort: this.state.sort_number, }).then(() => {
getContractsList({ dispatch: this.props.dispatch, order: this.state.order, sort: this.state.sort_number, all: this.state.all, }).then(() => {
this.setState({ loading: false });
}).catch(() => {});
});
@ -85,9 +86,9 @@ class IndexPage extends React.Component
_handle_onChangeSort_date = () =>
{
this.setState({ loading: true, sort_date: this.state.sort_date === "desc" ? "asc" : "desc" }, () =>
this.setState({ loading: true, order: "date", sort_date: this.state.sort_date === "desc" ? "asc" : "desc" }, () =>
{
getContractsList({ dispatch: this.props.dispatch, order: "date", sort: this.state.sort_date, }).then(() => {
getContractsList({ dispatch: this.props.dispatch, order: this.state.order, sort: this.state.sort_date, all: this.state.all, }).then(() => {
this.setState({ loading: false });
}).catch(() => {});
});
@ -95,9 +96,9 @@ class IndexPage extends React.Component
_handle_onChangeSort_status = () =>
{
this.setState({ loading: true, sort_status: this.state.sort_status === "desc" ? "asc" : "desc" }, () =>
this.setState({ loading: true, order: "status", sort_status: this.state.sort_status === "desc" ? "asc" : "desc" }, () =>
{
getContractsList({ dispatch: this.props.dispatch, order: "status", sort: this.state.sort_status, }).then(() => {
getContractsList({ dispatch: this.props.dispatch, order: this.state.order, sort: this.state.sort_status, all: this.state.all, }).then(() => {
this.setState({ loading: false });
}).catch(() => {});
});
@ -105,11 +106,23 @@ class IndexPage extends React.Component
_handle_onPage = (page) =>
{
const { sort_number, sort_status, search, date_from, date_to, } = this.state;
const { order, sort_number, sort_status, search, date_from, date_to, } = this.state;
this.setState({ loading: true, }, () =>
{
getContractsList({ dispatch: this.props.dispatch, sort_number, sort_status, search, date_from, date_to, page, }).then(() => {
getContractsList({ dispatch: this.props.dispatch, order, sort_number, sort_status, search, date_from, date_to, page, all: this.state.all, }).then(() => {
this.setState({ loading: false });
}).catch(() => {});
});
}
_handle_onAll = () =>
{
const { order, sort_number, sort_status, search, date_from, date_to, } = this.state;
this.setState({ loading: true, all: true }, () =>
{
getContractsList({ dispatch: this.props.dispatch, order, sort_number, sort_status, search, date_from, date_to, all: this.state.all, }).then(() => {
this.setState({ loading: false });
}).catch(() => {});
});
@ -121,7 +134,7 @@ class IndexPage extends React.Component
this.setState({ loading: true, }, () =>
{
getContractsList({ dispatch: this.props.dispatch, search, date_from, date_to, }).then(() => {
getContractsList({ dispatch: this.props.dispatch, search, date_from, date_to, all: this.state.all, }).then(() => {
this.setState({ loading: false });
}).catch(() => {});
});
@ -129,7 +142,7 @@ class IndexPage extends React.Component
render()
{
const { loading, page, pages, search, date_from, date_from_type, date_to, date_to_type, contracts, sort_number, sort_date, sort_status } = this.state;
const { loading, page, pages, search, date_from, date_from_type, date_to, date_to_type, contracts, sort_number, sort_date, sort_status, all } = this.state;
const contract_status = {
"Действующий": "opened",
"Закрыт": "closed",
@ -182,27 +195,29 @@ class IndexPage extends React.Component
<div className={`table_cell caret ${ sort_date === "asc" ? "reverse" : "" }`} onClick={ this._handle_onChangeSort_date }>Дата договора</div>
<div className="table_cell">Автомобиль</div>
<div className="table_cell">Гос.номер</div>
<div className="table_cell">Vin</div>
<div className="table_cell">VIN</div>
<div className={`table_cell caret ${ sort_status === "asc" ? "reverse" : "" }`} onClick={ this._handle_onChangeSort_status }>Статус</div>
<div className="table_cell">Следующий платеж</div>
</div>
{ contracts !== null && (
<>
{ contracts.length > 0 ? contracts.map((contract, index) => (
<div className="table_row" key={ index }>
<div className="table_cell"><Link href={`/contract/${ contract.number }/payments`}><a>Договор { contract.number }</a></Link></div>
<div className="table_cell">{ moment(contract.date).format("DD.MM.YYYY") }</div>
<div className="table_cell">{ contract.car?.brand?.name } { contract.car?.model?.name }</div>
<div className="table_cell">{ contract.car?.reg_number !== null ? contract.car?.reg_number : "Без рег. номера" }</div>
<div className="table_cell">{ contract.car?.vin_number }</div>
<div className="table_cell"><p className={ contract_status[contract.status] }>{ contract.status }</p></div>
<div className="table_cell">
{ contract.current_payment_amount !== null ? (
<>{ moment(contract.current_payment_date).format("DD.MM.YYYY") }<b className="price">{ numeral(contract.current_payment_amount).format('') } р.</b></>
) : "-" }
<Link href={`/contract/${ contract.number }/payments`}>
<div className="table_row" key={ index } style={{ cursor: "pointer" }}>
<div className="table_cell"><a>{ contract.number }</a></div>
<div className="table_cell">{ moment(contract.date).format("DD.MM.YYYY") }</div>
<div className="table_cell">{ contract.car?.brand?.name } { contract.car?.model?.name }</div>
<div className="table_cell">{ contract.car?.reg_number !== null ? contract.car?.reg_number : "Без рег. номера" }</div>
<div className="table_cell">{ contract.car?.vin_number }</div>
<div className="table_cell"><p className={ contract_status[contract.status] }>{ contract.status }</p></div>
<div className="table_cell">
{ contract.current_payment_date !== null ? (
<>{ moment(contract.current_payment_date).format("DD.MM.YYYY") }<b className="price">{ numeral(contract.current_payment_amount).format(' ., ') } </b></>
) : "-" }
</div>
</div>
</div>
)) : (
</Link>
)) : (
<div className="table_row">
<div className="table_cell">-</div>
<div className="table_cell">-</div>
@ -215,38 +230,10 @@ class IndexPage extends React.Component
) }
</>
) }
{/*
<div className="table_row">
<div className="table_cell"><Link href={`/contract/${ "1234-2022" }/payments`}>Договор 1234-2022</Link></div>
<div className="table_cell">21.02.2021</div>
<div className="table_cell">Lada Granta седан Standard 1.6 87hp 5MT</div>
<div className="table_cell">Х 123 АМ 777</div>
<div className="table_cell">4USBT53544LT26841</div>
<div className="table_cell">
<p className="opened">Действующий</p>
</div>
<div className="table_cell">
20.01.2021
<b className="price">45,000 р.</b>
</div>
</div>
<div className="table_row">
<div className="table_cell"><Link href={`/contract/${ "1234-2023" }/payments`}>Договор 1234-2023</Link></div>
<div className="table_cell">21.02.2021</div>
<div className="table_cell">Lada Granta седан Standard 1.6 87hp 5MT</div>
<div className="table_cell">Х 123 АМ 777</div>
<div className="table_cell">4USBT53544LT26841</div>
<div className="table_cell">
<p className="closed">Закрыт</p>
</div>
<div className="table_cell">
20.01.2021
<b className="price">45,000 р.</b>
</div>
</div>
*/}
</div>
<Pagination page={ page } pages={ pages } onPage={ this._handle_onPage }/>
{ !all && (
<Pagination page={ page } pages={ pages } onPage={ this._handle_onPage } onAll={ this._handle_onAll } all={ all } showAll={ true }/>
) }
</div>
</section>
</main>
@ -259,7 +246,6 @@ class IndexPage extends React.Component
function mapStateToProps(state, ownProps)
{
return {
company: state.company,
contracts: state.contracts.list,
page: state.contracts.page,
pages: state.contracts.pages,

View File

@ -67,7 +67,7 @@ class LoginPage extends React.Component
content="ЛК Эволюция автолизинга"
/>
</Head>
<MainHeader/>
<MainHeader logo_url={ process.env.NEXT_PUBLIC_MAIN_SITE } />
<main>
<section>
<div className="clear"></div>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 58 KiB

BIN
public/temp.pdf Normal file

Binary file not shown.

View File

@ -2007,6 +2007,11 @@ jest-worker@27.0.0-next.5:
merge-stream "^2.0.0"
supports-color "^8.0.0"
js-file-download@^0.4.12:
version "0.4.12"
resolved "https://registry.yarnpkg.com/js-file-download/-/js-file-download-0.4.12.tgz#10c70ef362559a5b23cdbdc3bd6f399c3d91d821"
integrity sha512-rML+NkoD08p5Dllpjo0ffy4jRHeY6Zsapvr/W86N7E0yuzAO6qa5X9+xog6zQNlH102J7IXljNY2FtS6Lj3ucg==
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"