From 3e2ab62bdd6abf7e56f267b7df945ffa70303d74 Mon Sep 17 00:00:00 2001 From: Dariiiii Date: Fri, 20 Dec 2024 03:45:49 +0300 Subject: [PATCH] big update front --- frontend/src/components/NavBar.vue | 4 +- frontend/src/router/index.js | 4 + frontend/src/views/CreditDetail.vue | 15 +- frontend/src/views/RequestDetail.vue | 7 +- .../src/views/admin/ClientCreditHistory.vue | 547 ++++++++++++++++++ frontend/src/views/admin/History.vue | 521 +++++++++++++++++ frontend/src/views/admin/Profile.vue | 228 +++++++- frontend/src/views/admin/Request.vue | 13 +- frontend/src/views/admin/Statistics.vue | 244 ++++---- frontend/src/views/client/Credit.vue | 79 +-- frontend/src/views/client/LoanApplication.vue | 71 ++- frontend/src/views/client/Main.vue | 115 +++- frontend/src/views/client/Profile.vue | 23 +- frontend/src/views/client/Request.vue | 8 +- 14 files changed, 1677 insertions(+), 202 deletions(-) create mode 100644 frontend/src/views/admin/ClientCreditHistory.vue create mode 100644 frontend/src/views/admin/History.vue diff --git a/frontend/src/components/NavBar.vue b/frontend/src/components/NavBar.vue index 2016303..2f40a7e 100644 --- a/frontend/src/components/NavBar.vue +++ b/frontend/src/components/NavBar.vue @@ -7,7 +7,7 @@
  • Заявки
  • Cтатистика
  • Заявки
  • - +
  • История
  • {{ userName }}
  • {{ userName }}
  • Выход
  • @@ -27,7 +27,7 @@ export default { return localStorage.getItem('userType') === 'admin'; }, userName() { - return localStorage.getItem('userName') || 'Пользователь'; + return localStorage.getItem('userName') || 'Не найдено'; }, isOnProfilePage() { return this.$route.path === '/client/profile' || this.$route.path === '/admin/profile'; diff --git a/frontend/src/router/index.js b/frontend/src/router/index.js index 6bcf484..7f5b363 100644 --- a/frontend/src/router/index.js +++ b/frontend/src/router/index.js @@ -12,6 +12,8 @@ import ClientLoanApplication from '../views/client/LoanApplication.vue'; import Statistics from '../views/admin/Statistics.vue'; import RequestDetail from '../views/RequestDetail.vue'; import CreditDetail from '../views/CreditDetail.vue'; +import History from '../views/admin/History.vue'; +import ClientCreditHistory from '../views/admin/ClientCreditHistory.vue'; const routes = [ // { path: '/', redirect: '/login' }, @@ -24,6 +26,8 @@ const routes = [ { path: '/admin/request', component: AdminRequest }, { path: '/request', component: RequestDetail}, { path: '/credit', component: CreditDetail }, + { path: '/history', component: History }, + { path: '/client_credit_history', component: ClientCreditHistory }, { path: '/client/profile', component: ClientProfile }, { path: '/admin/profile', component: AdminProfile }, { path: '/admin/statistics', component: Statistics }, diff --git a/frontend/src/views/CreditDetail.vue b/frontend/src/views/CreditDetail.vue index 1e2d4c3..f3055ae 100644 --- a/frontend/src/views/CreditDetail.vue +++ b/frontend/src/views/CreditDetail.vue @@ -3,7 +3,7 @@

    Детали кредита

    Название кредита: {{ request.loan_name }}
    -
    Дата открытия: {{ formatDate(request.opening_date) }}
    +
    Дата открытия: {{ formatDateTime(request.opening_date) }}
    Сумма: {{ request.amount }} руб.
    Ставка: {{ request.interest_rate }} %
    Срок: {{ request.expiration_time }} мес.
    @@ -30,6 +30,9 @@ export default { created() { this.getCreditDetails(); }, + mounted() { + document.title = "Детали кредита"; + }, methods: { async getCreditDetails() { try { @@ -44,7 +47,7 @@ export default { console.log('Ошибка при получении данных кредита:', error); } }, - formatDate(date) { + formatDateTime(date) { const options = { year: 'numeric', month: 'long', @@ -54,6 +57,14 @@ export default { second: '2-digit' }; return new Date(date).toLocaleString('ru-RU', options); + }, + formatDate(date) { + const options = { + year: 'numeric', + month: 'long', + day: 'numeric' + }; + return new Date(date).toLocaleString('ru-RU', options); } } }; diff --git a/frontend/src/views/RequestDetail.vue b/frontend/src/views/RequestDetail.vue index 186367f..954e86e 100644 --- a/frontend/src/views/RequestDetail.vue +++ b/frontend/src/views/RequestDetail.vue @@ -3,7 +3,7 @@

    Детали заявки

    Название кредита: {{ request.loan_name }}
    -
    Дата заявки: {{ formatDate(request.request_time) }}
    +
    Дата заявки: {{ formatDateTime(request.request_time) }}
    Статус: {{ request.status }}
    Сумма: {{ request.amount }} руб.
    Ставка: {{ request.interest_rate }} %
    @@ -44,6 +44,9 @@ export default { created() { this.getRequestDetails(); }, + mounted() { + document.title = "Детали заявки"; + }, methods: { async getRequestDetails() { try { @@ -59,7 +62,7 @@ export default { console.log('Ошибка при получении данных заявки:', error); } }, - formatDate(date) { + formatDateTime(date) { const options = { year: 'numeric', month: 'long', diff --git a/frontend/src/views/admin/ClientCreditHistory.vue b/frontend/src/views/admin/ClientCreditHistory.vue new file mode 100644 index 0000000..a973378 --- /dev/null +++ b/frontend/src/views/admin/ClientCreditHistory.vue @@ -0,0 +1,547 @@ + + + + \ No newline at end of file diff --git a/frontend/src/views/admin/History.vue b/frontend/src/views/admin/History.vue new file mode 100644 index 0000000..deb5b65 --- /dev/null +++ b/frontend/src/views/admin/History.vue @@ -0,0 +1,521 @@ + + + + + diff --git a/frontend/src/views/admin/Profile.vue b/frontend/src/views/admin/Profile.vue index cb67a0d..fd543be 100644 --- a/frontend/src/views/admin/Profile.vue +++ b/frontend/src/views/admin/Profile.vue @@ -1,30 +1,232 @@ \ No newline at end of file +.profile-container { + width: 80%; + max-width: 1400px; + margin: auto; + padding: 20px; + border: 1px solid #ddd; + border-radius: 10px; + background-color: #f9f9f9; +} + +.profile-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 20px; +} + +.profile-form { + display: flex; + justify-content: space-between; + gap: 50px; +} + +.profile-column { + flex: 1; +} + +.profile-field { + margin-bottom: 15px; +} + +label { + display: block; + margin-bottom: 5px; + font-weight: bold; +} + +input, +select { + width: 100%; + padding: 8px; + margin-top: 5px; + border: 1px solid #ddd; + border-radius: 4px; +} + +input:disabled, +select:disabled { + background-color: #f0f0f0; +} + +.date-input { + -webkit-appearance: none; + appearance: none; + position: relative; +} + diff --git a/frontend/src/views/admin/Request.vue b/frontend/src/views/admin/Request.vue index 5ed3ed9..cf33651 100644 --- a/frontend/src/views/admin/Request.vue +++ b/frontend/src/views/admin/Request.vue @@ -51,7 +51,6 @@
    -
    @@ -148,9 +147,9 @@ - {{ request.fio }} + {{ request.fio }} {{ request.loan_name }} - {{ formatDate(request.request_time) }} + {{ formatDateTime(request.request_time) }} {{ request.amount }} {{ request.interest_rate }} {{ request.expiration_time }} @@ -250,7 +249,7 @@ export default { } }, - resetFilters() { + resetFilters(flag=true) { this.loan_name = []; this.filters = { fio: '', @@ -266,7 +265,8 @@ export default { rating_from: '', rating_to: '' }; - this.getRequests(); + if (flag) + this.getRequests(); }, validateFilters() { @@ -342,6 +342,7 @@ export default { } }); this.requests = response.data; + this.resetFilters(false); } catch (error) { this.showNotification('Ошибка при применении сортировки!', 'error'); console.error('Ошибка при применении сортировки:', error); @@ -364,7 +365,7 @@ export default { this.fetchRequests(); }, - formatDate(date) { + formatDateTime(date) { const options = { year: 'numeric', month: 'long', diff --git a/frontend/src/views/admin/Statistics.vue b/frontend/src/views/admin/Statistics.vue index 2179b6d..17a9d9d 100644 --- a/frontend/src/views/admin/Statistics.vue +++ b/frontend/src/views/admin/Statistics.vue @@ -1,45 +1,59 @@ @@ -70,20 +78,22 @@ export default { }, data() { return { - selectedClientType: 'employee', - selectedName: '', - selectedCreditType: 'credit1', - selectedFilter: 'all', + selectedClientType: '', + fullName: '', + loanName: '', + filter: '', + measurements: { + amount: 'рубли', + expiration_time: 'месяцы', + }, notificationMessage: '', - notificationType: 'info', - showNotification: false, + notificationType: '', + isNotificationVisible: false, reloadFlag: false, userName: localStorage.getItem('userName') || 'Пользователь', - chartData: { - labels: [], - datasets: [] - }, - file: null + chart: null, + file: null, + fileName: '' }; }, mounted() { @@ -101,34 +111,27 @@ export default { link.setAttribute('download', 'exported_data.json'); document.body.appendChild(link); link.click(); - this.showNotification = true; - this.notificationMessage = 'Данные успешно экспортированы'; - this.notificationType = 'success'; + this.showNotification('Данные успешно экспортированы', 'success'); } catch (error) { - this.showNotification = true; - this.notificationMessage = 'Ошибка при экспорте данных'; - this.notificationType = 'error'; + this.showNotification('Ошибка при экспорте данных', 'error', error.message); console.error('Ошибка при экспорте данных:', error); } }, + handleFileUpload(event) { const file = event.target.files[0]; if (file && file.type === 'application/json') { this.file = file; - this.showNotification = true; - this.notificationMessage = 'Файл успешно загружен'; - this.notificationType = 'success'; + this.fileName = file.name; + this.showNotification('Файл успешно загружен', 'success'); } else { - this.showNotification = true; - this.notificationMessage = 'Пожалуйста, выберите файл формата JSON'; - this.notificationType = 'error'; + this.showNotification('Пожалуйста, выберите файл формата JSON', 'error'); } }, + async importData() { if (!this.file) { - this.showNotification = true; - this.notificationMessage = 'Пожалуйста, выберите файл для импорта'; - this.notificationType = 'error'; + this.showNotification('Пожалуйста, выберите файл для импорта', 'error'); return; } const formData = new FormData(); @@ -143,55 +146,47 @@ export default { }); localStorage.setItem('userName', response.data.adminName); this.reloadFlag = true; - this.showNotification = true; - this.notificationMessage = 'Данные успешно импортированы.'; - this.notificationType = 'success'; + this.showNotification('Данные успешно импортированы.', 'success'); } catch (error) { - this.showNotification = true; - this.notificationMessage = 'Ошибка при импорте данных'; - this.notificationType = 'error'; + this.showNotification('Ошибка при импорте данных', 'error', error.message); console.error('Ошибка при импорте данных:', error); } }, async buildChart() { try { - const response = await axios.get('http://127.0.0.1:5000/statistics', { + const response = await axios.get('http://127.0.0.1:5000/get_hist_data', { params: { - clientType: this.selectedClientType, - name: this.selectedName, - creditType: this.selectedCreditType, - filter: this.selectedFilter + // name: this.fullName, + credit_type: this.loanName, + filter_type: this.filter } }); - const data = response.data; - - this.chartData = { - labels: data.labels, - datasets: [{ - label: 'Сумма кредита', - data: data.values, - backgroundColor: 'rgba(139, 0, 139, 0.5)', - borderColor: 'rgba(139, 0, 139, 1)', - borderWidth: 1 - }] - }; - - this.renderChart(); + this.renderChart(data); } catch (error) { - this.showNotification = true; - this.notificationMessage = 'Ошибка при получении данных для построения графика'; - this.notificationType = 'error'; + this.showNotification('Ошибка при получении данных для построения графика', 'error', error.message); console.error('Ошибка при получении данных для построения графика:', error); } }, - renderChart() { + renderChart(data) { const ctx = document.getElementById('creditChart').getContext('2d'); - new Chart(ctx, { + if (this.chart) { + this.chart.destroy(); + } + this.chart = new Chart(ctx, { type: 'bar', - data: this.chartData, + data: { + labels: data.labels, + datasets: [{ + label: this.measurements[this.filter], + data: data.values, + backgroundColor: '#E3AFBC', + borderColor: '#9A1750', + borderWidth: 1 + }] + }, options: { scales: { y: { @@ -200,14 +195,21 @@ export default { } } }); + this.showNotification('Статистика успешно получена!', 'success'); }, closeNotification() { - this.showNotification = false; + this.isNotificationVisible = false; if (this.reloadFlag == true) { window.location.reload(); this.reloadFlag = false; } + }, + + showNotification(message, type, error_message = '') { + this.notificationMessage = message + " " + error_message; + this.notificationType = type; + this.isNotificationVisible = true; } } }; @@ -229,39 +231,74 @@ h1 { margin-top: 0; } -.filters-and-chart { +.content-wrapper { display: flex; width: 100%; } -.filters { +.filters-section { display: flex; flex-direction: column; width: 30%; margin-right: 20px; } -.filter { +.filter-item { + margin-top: 20px; margin-bottom: 10px; } -.filter label { +.filter-item label { display: block; margin-bottom: 5px; } -.filter select, .filter input { +.filter-item select { padding: 5px; width: 100%; } -.buttons { +.filter-item input { + padding: 5px; + width: 97%; +} + +.file-input-label { + display: inline-block; + padding: 10px 30px; + background-color: #E3AFBC; + border-radius: 4px; + cursor: pointer; + text-align: center; + width: 90%; +} + +.file-input-label span { + display: inline-block; + margin-right: 10px; +} + +.file-input { + display: none; +} + +.build-buttons { + margin-top: 20px; + display: flex; + flex-direction: column; +} +.build-buttons button { + padding: 0.5em 1em; + font-size: 0.9em; +} + +.action-buttons { display: flex; flex-direction: column; - gap: 10px; + gap: 20px; } -.buttons button { +.action-buttons button { padding: 0.5em 1em; font-size: 0.9em; } @@ -269,9 +306,10 @@ h1 { .chart-container { width: 70%; } + .chart { width: 100%; max-width: 800px; margin: 0 auto; } - \ No newline at end of file + diff --git a/frontend/src/views/client/Credit.vue b/frontend/src/views/client/Credit.vue index f18975d..0a4811c 100644 --- a/frontend/src/views/client/Credit.vue +++ b/frontend/src/views/client/Credit.vue @@ -1,5 +1,5 @@