/** @odoo-module **/
import { _t } from "@web/core/l10n/translation";
import { registry } from "@web/core/registry";
import { useService } from '@web/core/utils/hooks';
import { Component, onWillStart, useState } from "@odoo/owl";
const monthNames = [
"", "January", "February", "March", "April", "May", "June", "July",
"August", "September", "October", "November", "December"
];
export class TrainingDashboard extends Component {
static template = "TrainingDashboardMain";
setup(){
super.setup();
this.state = useState({
month: 1,
monthName: monthNames[1],
instructor: null,
instructorName: "Not Selected",
instructorsData: [],
year: null,
yearsData: [],
schedulesData: [],
noOfDaysData: [],
totalHoursData: 0,
loading: true,
});
this.action = useService("action");
onWillStart(async () => {
await this.loadDatas();
});
}
// -------------- On Clicking Buttons ---------------
onClickAddSchedule = () => {
this.action.doAction({
name: _t("My Planning"),
type: 'ir.actions.act_window',
res_model: 'training.slot',
view_mode: 'tree,form,calendar',
views: [[false, 'form']],
target: 'new',
});
}
onClickPrintSchedule = () => {
this.action.doAction({
name: _t("Print Schedule"),
type: 'ir.actions.act_window',
res_model: 'customer.schedule.report',
view_mode: 'tree,form',
views: [[false, 'form']],
target: 'new',
});
}
onClickPrint = () => {
this.action.doAction({
name: _t("Month Schedule"),
type: 'ir.actions.act_window',
res_model: 'schedule.board.print',
view_mode: 'form',
views: [[false, 'form']],
target: 'new',
});
}
onClickSearch = async () => {
this.state.loading = true;
const month = this.state.month;
const year = this.state.year;
const instructor = this.state.instructor;
const response = await fetch(`/api/get_custom_training_dashboard_datas?month=${month}&year=${year}&instructor=${instructor}`);
const data = await response.json();
console.log("data", data);
if (response.ok) {
this.state.noOfDaysData = data.response.no_of_days;
this.state.schedulesData = data.response.schedules;
this.state.totalHoursData = data.response.total_hours;
}
this.state.loading = false;
}
// ------------- Load Datas From API -------------------
async loadDatas() {
this.state.loading = true;
const response = await fetch('/api/get_training_dashboard_datas');
const data = await response.json();
console.log("data", data);
if (response.ok) {
this.state.yearsData = data.response.years;
this.state.year = Math.max(...data.response.years);
this.state.instructorsData = data.response.instructors;
this.state.instructor = data.response.instructors ? data.response.instructors[0].id : null;
this.state.noOfDaysData = data.response.no_of_days;
this.state.schedulesData = data.response.schedules;
this.state.totalHoursData = data.response.total_hours;
// Set initial values for monthName and instructorName based on data
this.updateMonthName();
this.updateInstructorName();
}
this.state.year = 2024;
this.state.month = 11;
this.state.instructor = 23;
this.state.loading = false;
}
// --------- Updaters Function ------------
// Update the displayed month name based on the current month value
updateMonthName() {
this.state.monthName = monthNames[this.state.month];
}
// Update displayed instructor name or default to "Not Selected"
updateInstructorName() {
const instructorId = Number(this.state.instructor);
const instructor = this.state.instructorsData.find(inst => inst.id === instructorId);
this.state.instructorName = instructor ? instructor.name : "Not Selected";
}
}
registry.category("actions").add("training_dashboard", TrainingDashboard);
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<t t-name="TrainingDashboardMain">
<style>
table, th, td {
border: 1px solid black;
}
th, td {
text-align: center;
max-width: 50px;
word-wrap: break-word;
}
thead th {
background-color: #ABDD93;
position: sticky;
top: 0;
z-index: 1;
}
.dashboard-container {
padding: 15px;
position: relative;
}
.filter-container {
display: flex;
flex-wrap: wrap;
gap: 10px;
align-items: center;
}
/* Loader styling */
.loading-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
background: rgba(255, 255, 255, 0.7);
z-index: 1000;
}
.spinner-border {
width: 3rem;
height: 3rem;
}
@media (max-width: 576px) {
.dashboard-buttons, .filter-container {
justify-content: center;
}
.filter-container .col {
width: 100%;
text-align: center;
}
}
</style>
<div class="dashboard-container">
<!-- Loader overlay -->
<t t-if="state.loading">
<div class="loading-overlay">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
</t>
<!-- Dashboard Content -->
<div class="row">
<!-- Left side buttons -->
<div class="col-md-6 col-12 row gap-3 border-end">
<div class="col-12">
<div class="d-flex justify-content-between align-items-center">
<h5>Instructor: <span class="fw-bolder" t-esc="state.instructorName || 'Not Selected'"/></h5>
<h5>Month: <span class="fw-bolder" t-esc="state.monthName"/></h5>
<h5>Year: <span class="fw-bolder" t-esc="state.year"/></h5>
</div>
<h5>Total Hours: <span class="fw-bolder" t-esc="state.totalHoursData"/></h5>
</div>
<div class="col-12 d-flex justify-content-start align-items-end">
<button class="btn btn-warning btn-sm rounded-pill me-2 fw-bolder text-white "
type="button" t-on-click="() => onClickAddSchedule()">Add Schedule</button>
<button class="btn btn-success btn-sm rounded-pill me-2 fw-bolder"
type="button" t-on-click="() => onClickPrintSchedule()">Print Schedule</button>
<button class="btn btn-primary btn-sm rounded-pill fw-bolder" type="button"
t-on-click="() => onClickPrint()">Print</button>
</div>
</div>
<!-- Right side filters and search button -->
<div class="col-md-6 col-12 filter-container d-flex justify-content-center align-items-center">
<div class="col-auto">
<label for="inst" class="form-label">Instructor</label>
<select t-model="state.instructor" class="form-select form-select-sm"
t-on-change="updateInstructorName">
<t t-foreach="state.instructorsData" t-as="instructor" t-key="instructor.id">
<option t-att-value="instructor.id"><t t-esc="instructor.name"/></option>
</t>
</select>
</div>
<div class="col-auto">
<label for="month" class="form-label">Month</label>
<select t-model="state.month" class="form-select form-select-sm" t-on-change="updateMonthName">
<option value="1">January</option>
<option value="2">February</option>
<option value="3">March</option>
<option value="4">April</option>
<option value="5">May</option>
<option value="6">June</option>
<option value="7">July</option>
<option value="8">August</option>
<option value="9">September</option>
<option value="10">October</option>
<option value="11">November</option>
<option value="12">December</option>
</select>
</div>
<div class="col-auto">
<label for="year" class="form-label">Year</label>
<select t-model="state.year" class="form-select form-select-sm">
<t t-foreach="state.yearsData" t-as="year" t-key="year">
<option t-att-value="year"><t t-esc="year"/></option>
</t>
</select>
</div>
<div class="col-auto">
<button class="btn btn-primary btn-sm rounded mt-md-4" type="button"
t-on-click="() => onClickSearch()">Search</button>
</div>
</div>
</div>
<hr class="my-2"/>
<!-- datas -->
<div class="row">
<div class="col-sm-12 col-lg-12 leave-manager">
<div style="overflow-y:auto; height: 500px;border: 1px solid black;border-radius: 7px;width:100%;">
<table style="border: 1px solid black;border-radius: 7px;width:100%;height:100%">
<thead>
<tr>
<th class="fw-bolder">Time/Date</th>
<t t-foreach="state.noOfDaysData" t-as="day" t-key="day">
<th class="fw-bolder"><t t-esc="day"/></th>
</t>
</tr>
</thead>
<tbody>
<t t-foreach="state.schedulesData" t-as="schedule" t-key="schedule">
<tr>
<t t-foreach="schedule" t-as="data" t-key="data">
<t t-if="data.code=='N'">
<td><t t-esc="data.value"/></td>
</t>
<t t-elif="data.code=='F'">
<td bgcolor="#F0F042"><t t-esc="data.value"/></td>
</t>
<t t-elif="data.code=='L'">
<td bgcolor="#ED8A49"><t t-esc="data.value"/></td>
</t>
<t t-elif="data.code=='P'">
<td style="color:#DB6262"><t t-esc="data.value"/></td>
</t>
<t t-elif="data.code=='R'">
<td><t t-esc="data.value"/></td>
</t>
<t t-elif="data.code=='FP'">
<td style="color:#DB6262;background-color: #F0F042;"><t t-esc="data.value"/></td>
</t>
<t t-elif="data.code=='FR'">
<td style="color:#0A0000;background-color: #F0F042;"><t t-esc="data.value"/></td>
</t>
</t>
</tr>
</t>
</tbody>
</table>
</div>
</div>
</div>
</div>
</t>
<t t-name="EmployeeWarning">
<div>
<p>Error : Could not find employee linked to user</p>
<p>Please contact system admin for the setup</p>
</div>
</t>
</templates>
Odoo is the world's easiest all-in-one management software.
It includes hundreds of business apps:
- CRM
- e-Commerce
- Boekhouding
- Voorraad
- PoS
- Project
- MRP
Deze vraag is gerapporteerd
De vraag is gesloten voor reden: Question / Code not indented
door Rakesh Patel (patr) met 07-11-2024 01:47:15
door Rakesh Patel (patr) met 07-11-2024 01:47:15
1641
Weergaven
Geniet je van het gesprek? Blijf niet alleen lezen, doe ook mee!
Maak vandaag nog een account aan om te profiteren van exclusieve functies en deel uit te maken van onze geweldige community!
AanmeldenGerelateerde posts | Antwoorden | Weergaven | Activiteit | |
---|---|---|---|---|
|
2
okt. 24
|
3996 | ||
|
1
mei 24
|
1465 | ||
Odoo 16 Migrations Error
Opgelost
|
|
1
okt. 23
|
2253 | |
|
1
dec. 22
|
2697 | ||
|
0
okt. 22
|
1469 |