- Replaced duplicate date-handling logic in multiple components (e.g., `CountryProperties.vue`, `Rates.vue`, `ErrorLog.vue`) with centralized `buildDate` method from `common.js`. - Improved date consistency and readability by adopting `YYYY/MM/DD` format with optional time support.
280 lines
No EOL
8.5 KiB
Vue
280 lines
No EOL
8.5 KiB
Vue
<template>
|
|
<div class="container-rate-container">
|
|
|
|
<staged-rates ref="stagedRatesRef" @rates-update="reloadTable"></staged-rates>
|
|
|
|
<div class="container-rate-header">
|
|
|
|
<div class="container-rate-search-container">
|
|
<span class="period-select-caption">Rate type:</span>
|
|
<radio-option name="rateType" value="container" v-model="rateType">Container rates</radio-option>
|
|
<radio-option name="rateType" value="matrix" v-model="rateType">Kilometer rates</radio-option>
|
|
</div>
|
|
|
|
<div v-if="!loadingPeriods" class="period-select-container">
|
|
<span class="period-select-caption">Validity period:</span>
|
|
<dropdown :options="periods"
|
|
emptyText="No validity period available"
|
|
class="period-select"
|
|
placeholder="Select a validity period"
|
|
v-model="selectedPeriod"
|
|
></dropdown>
|
|
<tooltip position="left" text="Invalidate the selected validity period">
|
|
<icon-button icon="trash" @click="deletePeriod" :disabled="disableDeleteButton"></icon-button>
|
|
</tooltip>
|
|
<modal-dialog title="Do you really want to invalidate this validity period?"
|
|
dismiss-text="No"
|
|
accept-text="Yes"
|
|
:state="modalDialogDeleteState"
|
|
message="If you invalidate this property set, this will also invalidate all calculations done with this property set. This cannot be undone!"
|
|
@click="deleteModalClick"
|
|
>
|
|
</modal-dialog>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<table-view ref="tableViewRef" :data-source="fetch" :columns="selectedTypeColumns" :page="pagination.page"
|
|
:page-size="pageSize" :page-count="pagination.pageCount"
|
|
:total-count="pagination.totalCount"></table-view>
|
|
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
<script>
|
|
import Dropdown from "@/components/UI/Dropdown.vue";
|
|
import IconButton from "@/components/UI/IconButton.vue";
|
|
import Tooltip from "@/components/UI/Tooltip.vue";
|
|
import ModalDialog from "@/components/UI/ModalDialog.vue";
|
|
import {mapStores} from "pinia";
|
|
import {useValidityPeriodStore} from "@/store/validityPeriod.js";
|
|
import AutosuggestSearchbar from "@/components/UI/AutoSuggestSearchBar.vue";
|
|
import DataTable from "@/components/UI/DataTable.vue";
|
|
import TableView from "@/components/UI/TableView.vue";
|
|
import RadioOption from "@/components/UI/RadioOption.vue";
|
|
import {useMatrixRateStore} from "@/store/matrixRate.js";
|
|
import {useContainerRateStore} from "@/store/containerRate.js";
|
|
import StagedRates from "@/components/layout/config/StagedRates.vue";
|
|
import {buildDate} from "@/common.js";
|
|
|
|
export default {
|
|
name: "Rates",
|
|
props: {
|
|
isSelected: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
},
|
|
watch: {
|
|
async isSelected(newVal) {
|
|
if (newVal === true) {
|
|
await this.validityPeriodStore.loadPeriods();
|
|
await this.matrixRateStore.setQuery();
|
|
await this.containerRateStore.setQuery();
|
|
this.$refs.stagedRatesRef.checkChanges();
|
|
this.pagination = this.rateType === 'container' ? this.containerRateStore.getPagination : this.matrixRateStore.getPagination;
|
|
}
|
|
}
|
|
},
|
|
components: {
|
|
StagedRates,
|
|
RadioOption, TableView, DataTable, AutosuggestSearchbar, ModalDialog, Tooltip, IconButton, Dropdown
|
|
},
|
|
computed: {
|
|
...mapStores(useValidityPeriodStore, useMatrixRateStore, useContainerRateStore),
|
|
loadingPeriods() {
|
|
// return this.propertiesStore.isLoading;
|
|
return false;
|
|
},
|
|
isValidPeriodActive() {
|
|
const state = this.validityPeriodStore.getPeriodState(this.selectedPeriod);
|
|
return state === "VALID" || state === "DRAFT";
|
|
},
|
|
disableDeleteButton() {
|
|
const state = this.validityPeriodStore.getPeriodState(this.selectedPeriod);
|
|
return state === "VALID" || state === "INVALID" || state === "DRAFT";
|
|
},
|
|
rateType: {
|
|
get() {
|
|
return this.rateTypeValue;
|
|
},
|
|
set(value) {
|
|
|
|
if (value === "matrix") {
|
|
this.selectedTypeColumns = this.matrixColumns;
|
|
} else {
|
|
this.selectedTypeColumns = this.containerColumns;
|
|
}
|
|
|
|
this.rateTypeValue = value;
|
|
this.$refs.tableViewRef.reload('', 1);
|
|
}
|
|
},
|
|
selectedPeriod: {
|
|
get() {
|
|
return this.validityPeriodStore.getSelectedPeriod
|
|
},
|
|
async set(value) {
|
|
this.validityPeriodStore.setSelectedPeriod(value);
|
|
this.$refs.tableViewRef.reload('', 1);
|
|
}
|
|
},
|
|
periods() {
|
|
const periods = [];
|
|
|
|
const vp = this.validityPeriodStore.getPeriods;
|
|
|
|
if ((vp ?? null) === null) {
|
|
return null;
|
|
}
|
|
|
|
for (const p of vp) {
|
|
const value = (p.state === "DRAFT") ? "DRAFT" : (p.state === "VALID") ? "CURRENT" : `${this.buildDate(p.start_date)} - ${this.buildDate(p.end_date)} ${p.state === "INVALID" ? "(INVALID)" : ""}`;
|
|
const period = {id: p.id, value: value};
|
|
|
|
|
|
periods.push(period);
|
|
}
|
|
|
|
return periods;
|
|
}
|
|
},
|
|
data() {
|
|
return {
|
|
pageSize: 20,
|
|
pagination: {page: 1, pageCount: 1, totalCount: 1},
|
|
rateTypeValue: "container",
|
|
selectedTypeColumns: [],
|
|
matrixColumns: [
|
|
{key: 'source.iso_code', label: 'From Country (ISO code)'},
|
|
{key: 'destination.iso_code', label: 'To Country (ISO code)'},
|
|
{key: 'rate', align: 'right', label: 'Rate [EUR/km]'},
|
|
],
|
|
containerColumns: [
|
|
{
|
|
key: 'type', label: 'Type', align: 'center', iconResolver: (rawValue, _) => {
|
|
|
|
if (rawValue === "SEA") {
|
|
return "PhBoat";
|
|
} else if (rawValue === "RAIL") {
|
|
return "PhTrain"
|
|
} else if (rawValue === "ROAD" || rawValue === "POST_RUN") {
|
|
return "PhTruck"
|
|
}
|
|
}
|
|
},
|
|
{key: 'source.name', align: 'left', label: 'From node'},
|
|
{key: 'destination.name', align: 'left', label: 'To node'},
|
|
{key: 'rates.TEU', align: 'right', label: '20 ft. GP rate [EUR]'},
|
|
{key: 'rates.FEU', align: 'right', label: '40 ft. GP rate [EUR]'},
|
|
{key: 'rates.HC', align: 'right', label: '40 ft. HC rate [EUR]'},
|
|
{key: 'lead_time', align: 'right', label: 'Lead time [days]'},
|
|
],
|
|
modalDialogDeleteState: false,
|
|
selectedPeriodId: null
|
|
}
|
|
},
|
|
async created() {
|
|
this.selectedTypeColumns = this.containerColumns;
|
|
await this.validityPeriodStore.loadPeriods();
|
|
await this.matrixRateStore.setQuery();
|
|
await this.containerRateStore.setQuery();
|
|
this.pagination = this.rateType === 'container' ? this.containerRateStore.getPagination : this.matrixRateStore.getPagination;
|
|
},
|
|
methods: {
|
|
buildDate(date) {
|
|
return buildDate(date, false);
|
|
},
|
|
async fetch(query) {
|
|
|
|
query.periodId = this.selectedPeriod;
|
|
|
|
if (this.rateType === "container") {
|
|
await this.containerRateStore.setQuery(query);
|
|
this.pagination = this.containerRateStore.getPagination;
|
|
|
|
return this.containerRateStore.getRates;
|
|
} else if (this.rateType === "matrix") {
|
|
await this.matrixRateStore.setQuery(query);
|
|
|
|
this.pagination = this.matrixRateStore.getPagination;
|
|
return this.matrixRateStore.getRates;
|
|
}
|
|
return [];
|
|
},
|
|
deletePeriod() {
|
|
if (!this.disableDeleteButton) {
|
|
this.modalDialogDeleteState = true;
|
|
}
|
|
},
|
|
async reloadTable() {
|
|
await this.validityPeriodStore.loadPeriods();
|
|
await this.matrixRateStore.setQuery();
|
|
await this.containerRateStore.setQuery();
|
|
this.pagination = this.rateType === 'container' ? this.containerRateStore.getPagination : this.matrixRateStore.getPagination;
|
|
},
|
|
deleteModalClick() {
|
|
this.modalDialogDeleteState = false;
|
|
|
|
if (action === 'accept')
|
|
this.validPeriodStore.invalidate();
|
|
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
|
.table-view {
|
|
margin-top: 1.6rem;
|
|
}
|
|
|
|
.container-rate-container {
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.container-rate-header {
|
|
display: flex;
|
|
flex-direction: row;
|
|
justify-content: space-between;
|
|
align-items: flex-end;
|
|
gap: 3.2rem;
|
|
}
|
|
|
|
.container-rate-search-container {
|
|
display: flex;
|
|
justify-content: stretch;
|
|
align-items: center;
|
|
flex: 1;
|
|
margin-bottom: 1rem;
|
|
gap: 1.6rem;
|
|
font-size: 1.4rem;
|
|
|
|
}
|
|
|
|
.container-rate-search-searchbar {
|
|
flex: 1;
|
|
}
|
|
|
|
.period-select-container {
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
align-items: center;
|
|
margin-bottom: 1rem;
|
|
gap: 1.6rem;
|
|
font-size: 1.4rem;
|
|
min-width: 50rem;
|
|
}
|
|
|
|
.period-select-caption {
|
|
font-weight: 500;
|
|
}
|
|
|
|
|
|
</style> |