| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| |
| <template> |
| <div> |
| <filter-quota-data-by-period-view @fetchData="fetchData"/> |
| |
| <div v-if="dataSource.length > 0"> |
| <hr class="m-20-0" /> |
| <div class="chart-row"> |
| <a-space direction="vertical"> |
| <div> |
| <a-radio-group |
| v-model:value="graphType" |
| buttonStyle="solid"> |
| <a-radio-button value="bar_chart"> |
| {{ $t('label.total') }} |
| </a-radio-button> |
| <a-radio-button value="line_chart"> |
| {{ $t('label.quota.statement.history') }} |
| </a-radio-button> |
| <a-radio-button value="incremental_chart"> |
| {{ $t('label.quota.statement.cumulative.history') }} |
| </a-radio-button> |
| </a-radio-group> |
| </div> |
| </a-space> |
| </div> |
| <div style="font-size: 18px"> |
| <strong> {{ $t('label.quota.usage.types.summary') }} </strong> |
| </div> |
| <export-to-csv-button :action="exportDataToCsv" /> |
| <bar-chart v-if="graphType === 'bar_chart'" :chart-options="getBarChartOptions()" :chart-data="getUsageTypeBarChartData()"/> |
| <resource-stats-line-chart |
| v-else |
| :chart-labels="usageLineChartLabels" |
| :chart-data="getEntryForCurrentGraphType(this.usageLineChartData)" |
| :yAxisIncrementValue="getYAxisIncrement(getEntryForCurrentGraphType(this.YAxisMax.usageTypes))" |
| :yAxisMeasurementUnit="''" |
| /> |
| <a-table |
| size="small" |
| :loading="loading" |
| :columns="columns" |
| :dataSource="dataSource.filter(row => row.quota > 0)" |
| :rowKey="record => record.name" |
| :pagination="false" |
| :scroll="{ y: '55vh' }"> |
| <template #bodyCell="{ column, text, record }"> |
| <template v-if="column.dataIndex === 'name'"> |
| <a @click="handleSelectedTypeChange(`${record.type}-${record.name}`)">{{ $t(text) }}</a> |
| </template> |
| <template v-if="column.dataIndex === 'unit'"> |
| {{ $t(text) }} |
| </template> |
| <template v-if="column.dataIndex === 'quota'"> |
| <a-tooltip placement="right"> |
| <template #title> |
| {{ text }} |
| </template> |
| <span class="dotted-underline">{{ parseFloat(text).toFixed(2) }}</span> |
| </a-tooltip> |
| </template> |
| </template> |
| <template #footer > |
| <div style="text-align: right;"> |
| {{ $t('label.currency') }}: <b>{{ currency }}</b><br/> |
| {{ $t('label.quota.total.consumption') }}: |
| <a-tooltip placement="bottom"> |
| <template #title> |
| {{ totalQuota }} |
| </template> |
| <b class="dotted-underline">{{ parseFloat(totalQuota).toFixed(2) }}</b> |
| </a-tooltip> |
| </div> |
| </template> |
| </a-table> |
| |
| <hr class="m-20-0" id="resource-by-type" /> |
| <strong> |
| <tooltip-label style="font-size: 18px" :title="$t('label.quota.usage.resources.by.type')" :tooltip="$t('message.quota.usage.resource.warn')"/> |
| </strong> |
| <a-select |
| v-model:value="selectedType" |
| class="w-100" |
| style="margin: 5px 0 10px 0px" |
| show-search |
| @change="handleSelectedTypeChange"> |
| <a-select-option |
| v-for="quotaType of getQuotaTypesFiltered()" |
| :value="`${quotaType.id}-${quotaType.type}`" |
| :key="quotaType.id"> |
| {{ $t(quotaType.type) }} |
| </a-select-option> |
| </a-select> |
| <export-to-csv-button v-if="dataSourceResource.length > 0" :action="exportResourcesToCsv" :label="`label.export.resources.csv`" /> |
| <bar-chart v-if="dataSourceResource.length > 0 && graphType === 'bar_chart'" :chart-options="getBarChartOptions()" :chart-data="getResourceBarChartData()"/> |
| <resource-stats-line-chart |
| v-else-if="dataSourceResource.length > 0 && graphType !== 'bar_chart'" |
| :chart-labels="resourceLineChartLabels" |
| :chart-data="getEntryForCurrentGraphType(this.resourceLineChartData)" |
| :yAxisIncrementValue="getYAxisIncrement(getEntryForCurrentGraphType(this.YAxisMax.resources))" |
| :yAxisMeasurementUnit="''" |
| /> |
| <a-table |
| size="small" |
| :loading="loadingResources" |
| :columns="resourceColumns" |
| :dataSource="dataSourceResource" |
| :rowKey="(record) => record.displayname" |
| :pagination="false" |
| :scroll="{ y: '55vh' }"> |
| <template #title v-if="dataSourceResource.length > 0"> |
| <div>{{ $t('label.currency') }}: <b>{{ currency }}</b></div> |
| </template> |
| <template #bodyCell="{ column, text, record }"> |
| <template v-if="column.dataIndex === 'displayname'"> |
| <span v-if="!text"> |
| - |
| </span> |
| <span v-if="text === '<untraceable>' || !record.resourceid"> |
| {{ text }} |
| </span> |
| <a v-else @click="handleSelectedResourceChange(record.resourceid)"> |
| {{ text }} |
| </a> |
| </template> |
| <template v-if="column.dataIndex === 'quotaconsumed'"> |
| <a-tooltip placement="right"> |
| <template #title> |
| {{ text }} |
| </template> |
| <span class="dotted-underline">{{ parseFloat(text).toFixed(2) }}</span> |
| </a-tooltip> |
| </template> |
| </template> |
| </a-table> |
| |
| <hr class="m-20-0" id="details-by-resource" /> |
| <strong> |
| <tooltip-label style="font-size: 18px" :title="$t('label.quota.usage.details.by.resource')"/> |
| </strong> |
| <a-select |
| v-model:value="selectedResource" |
| class="w-100" |
| style="margin: 5px 0 10px 0px" |
| show-search |
| @change="handleSelectedResourceChange" |
| :disabled="getResources().length == 0"> |
| <a-select-option |
| v-for="item of getResources()" |
| :value="item.id" |
| :key="item.id"> |
| {{ $t(item.name) }} |
| </a-select-option> |
| </a-select> |
| <export-to-csv-button v-if="dataSourceTariffs.length > 0" :action="exportResourceDetailsToCsv" :label="`label.export.details.csv`" /> |
| <bar-chart v-if="dataSourceTariffs.length > 0 && graphType === 'bar_chart'" :chart-options="getBarChartOptions()" :chart-data="getTariffsBarChartData()"/> |
| <resource-stats-line-chart |
| v-else-if="dataSourceTariffs.length > 0 && graphType !== 'bar_chart'" |
| :chart-labels="tariffLineChartLabels" |
| :chart-data="getEntryForCurrentGraphType(this.tariffLineChartData)" |
| :yAxisIncrementValue="getYAxisIncrement(getEntryForCurrentGraphType(this.YAxisMax.tariffs))" |
| :yAxisMeasurementUnit="''" |
| /> |
| <a-table |
| size="small" |
| :loading="loadingTariffs" |
| :columns="resourceDetailsColumns" |
| :dataSource="dataSourceTariffs" |
| :rowKey="record => record.tariffname + '-' + record.startdate" |
| :pagination="false" |
| :scroll="{ y: '55vh' }"> |
| <template #title v-if="dataSourceTariffs.length > 0"> |
| <div>{{ $t('label.currency') }}: <b>{{ currency }}</b></div> |
| </template> |
| <template #bodyCell="{ column, text, record }"> |
| <template v-if="column.dataIndex === 'tariffname'"> |
| <a v-if="'quotaTariffList' in $store.getters.apis" :href="`#/quotatariff/${record.tariffid}`" target="_blank"> |
| {{ text }} |
| </a> |
| <span v-else> |
| {{ text }} |
| </span> |
| </template> |
| <template v-if="column.dataIndex === 'enddate'"> |
| {{ $toLocaleDate(text) }} |
| </template> |
| <template v-if="column.dataIndex === 'startdate'"> |
| {{ $toLocaleDate(text) }} |
| </template> |
| <template v-if="column.dataIndex === 'quotaconsumed'"> |
| <a-tooltip placement="right"> |
| <template #title> |
| {{ text }} |
| </template> |
| <span class="dotted-underline">{{ parseFloat(text).toFixed(2) }}</span> |
| </a-tooltip> |
| </template> |
| </template> |
| </a-table> |
| </div> |
| </div> |
| </template> |
| |
| <script> |
| import { getAPI } from '@/api' |
| import FilterQuotaDataByPeriodView from './FilterQuotaDataByPeriodView.vue' |
| import BarChart from '@/components/view/charts/BarChart.vue' |
| import ResourceStatsLineChart from '@/components/view/stats/ResourceStatsLineChart.vue' |
| import ExportToCsvButton from '@/components/view/buttons/ExportToCsvButton.vue' |
| import { getChartColorObject } from '@/utils/chart' |
| import { getQuotaTypeByName, getQuotaTypes } from '@/utils/quota' |
| import TooltipLabel from '@/components/widgets/TooltipLabel' |
| import { downloadDataAsCsv } from '@/utils/util.js' |
| import * as dateUtils from '@/utils/date' |
| |
| export default { |
| name: 'QuotaUsageTab', |
| components: { |
| FilterQuotaDataByPeriodView, |
| BarChart, |
| ExportToCsvButton, |
| ResourceStatsLineChart, |
| TooltipLabel |
| }, |
| data () { |
| return { |
| dataSource: [], |
| selectedType: '', |
| loadingResources: false, |
| dataSourceResource: [], |
| selectedResource: '', |
| loadingTariffs: false, |
| dataSourceTariffs: [], |
| startDate: undefined, |
| endDate: undefined, |
| graphType: 'bar_chart', |
| usageLineChartLabels: [], |
| resourceLineChartLabels: [], |
| tariffLineChartLabels: [], |
| usageLineChartData: {}, |
| resourceLineChartData: {}, |
| tariffLineChartData: {}, |
| YAxisMax: {} |
| } |
| }, |
| watch: { |
| graphType (newGraphType) { |
| if (newGraphType === 'bar_chart') { |
| return |
| } |
| this.prepareDataForUsageTypeLineGraph() |
| if (!this.selectedType) { |
| return |
| } |
| this.prepareDataForResourceLineGraph() |
| if (!this.selectedResource) { |
| return |
| } |
| this.prepareDataForTariffLineGraph() |
| } |
| }, |
| computed: { |
| columns () { |
| return [ |
| { |
| title: this.$t('label.quota.type.name'), |
| dataIndex: 'name', |
| width: 'calc(100% / 3)', |
| sorter: (a, b) => a.name.localeCompare(b.name) |
| }, |
| { |
| title: this.$t('label.quota.type.unit'), |
| dataIndex: 'unit', |
| width: 'calc(100% / 3)', |
| sorter: (a, b) => a.unit.localeCompare(b.unit) |
| }, |
| { |
| title: this.$t('label.quota.consumed'), |
| dataIndex: 'quota', |
| width: 'calc(100% / 3)', |
| sorter: (a, b) => a.quota - b.quota, |
| defaultSortOrder: 'descend' |
| } |
| ] |
| }, |
| resourceColumns () { |
| return [ |
| { |
| title: this.$t('label.resource'), |
| dataIndex: 'displayname', |
| width: '50%', |
| sorter: (a, b) => a.displayname.localeCompare(b.displayname), |
| defaultSortOrder: 'ascend' |
| }, |
| { |
| title: this.$t('label.quota.consumed'), |
| dataIndex: 'quotaconsumed', |
| width: '50%', |
| sorter: (a, b) => a.quotaconsumed - b.quotaconsumed |
| } |
| ] |
| }, |
| resourceDetailsColumns () { |
| return [ |
| { |
| title: this.$t('label.quota.tariff'), |
| dataIndex: 'tariffname', |
| sorter: (a, b) => a.tariffname.localeCompare(b.tariffname) |
| }, |
| { |
| title: this.$t('label.start.date'), |
| dataIndex: 'startdate', |
| sorter: (a, b) => a.startdate.localeCompare(b.startdate), |
| defaultSortOrder: 'descend' |
| }, |
| { |
| title: this.$t('label.end.date'), |
| dataIndex: 'enddate', |
| sorter: (a, b) => a.enddate.localeCompare(b.enddate) |
| }, |
| { |
| title: this.$t('label.quota.consumed'), |
| dataIndex: 'quotaconsumed', |
| sorter: (a, b) => a.quotaconsumed - b.quotaconsumed |
| } |
| ] |
| } |
| }, |
| methods: { |
| async fetchData (startDate, endDate, keepMoment = true) { |
| if (this.loading) return |
| |
| this.startDate = dateUtils.parseDayJsObject({ value: startDate, keepMoment: keepMoment }) |
| this.endDate = dateUtils.parseDayJsObject({ value: endDate, keepMoment: keepMoment }) |
| this.loading = true |
| this.dataSource = [] |
| this.dataSourceResource = [] |
| this.dataSourceTariffs = [] |
| this.selectedResource = '' |
| this.selectedType = '' |
| |
| try { |
| const quotaStatement = await this.getQuotaStatement({ |
| startdate: this.startDate, |
| enddate: this.endDate |
| }) |
| |
| if (!quotaStatement) { |
| return |
| } |
| |
| this.dataSource = quotaStatement.quotausage.filter(row => row.quota !== 0) |
| if (this.dataSource.length === 0) { |
| this.$notification.info({ message: this.$t('message.request.no.data') }) |
| } |
| |
| this.currency = quotaStatement.currency |
| this.totalQuota = quotaStatement.totalquota |
| if (this.graphType !== 'bar_chart') { |
| this.prepareDataForUsageTypeLineGraph() |
| } |
| } finally { |
| this.loading = false |
| } |
| }, |
| async fetchResourceData () { |
| if (this.selectedType === '' || this.loadingResources) return |
| |
| this.dataSourceResource = [] |
| this.loadingResources = true |
| |
| try { |
| const quotaStatement = await this.getQuotaStatement({ |
| startdate: this.startDate, |
| enddate: this.endDate, |
| showresources: true, |
| type: this.selectedType.split('-')[0] |
| }) |
| |
| this.dataSourceResource = quotaStatement.quotausage[0].resources.filter(row => row.quotaconsumed !== 0) |
| if (this.dataSourceResource.length === 0) { |
| this.$notification.info({ message: this.$t('message.request.no.data') }) |
| } |
| |
| if (this.graphType !== 'bar_chart') { |
| this.prepareDataForResourceLineGraph() |
| } |
| } finally { |
| this.loadingResources = false |
| } |
| }, |
| async fetchTariffData () { |
| if (this.selectedResource === '' || this.loadingTariffs) return |
| |
| this.dataSourceTariffs = [] |
| this.loadingTariffs = true |
| |
| try { |
| const quotaResourceStatement = await getAPI('quotaResourceStatement', { |
| startdate: this.startDate, |
| enddate: this.endDate, |
| usagetype: this.selectedType.split('-')[0], |
| id: this.selectedResource, |
| accountid: this.$route.params?.id, |
| ignoreproject: true |
| }).then(json => json.quotaresourcestatementresponse?.quotaresourcestatement?.items || []) |
| |
| this.dataSourceTariffs = quotaResourceStatement.map(quotaUsage => ({ |
| ...quotaUsage, |
| startdate: dateUtils.parseDayJsObject({ value: quotaUsage.startdate, keepMoment: false }), |
| enddate: dateUtils.parseDayJsObject({ value: quotaUsage.enddate, keepMoment: false }) |
| })).filter(row => row.quotaconsumed !== 0) |
| if (this.dataSourceTariffs.length === 0) { |
| this.$notification.info({ message: this.$t('message.request.no.data') }) |
| } |
| |
| if (this.graphType !== 'bar_chart') { |
| this.prepareDataForTariffLineGraph() |
| } |
| } finally { |
| this.loadingTariffs = false |
| } |
| }, |
| async getQuotaStatement (apiParams) { |
| const params = { |
| ignoreproject: true, |
| accountid: this.$route.params?.id, |
| ...apiParams |
| } |
| |
| return await getAPI('quotaStatement', params) |
| .then(json => json.quotastatementresponse.statement || {}) |
| }, |
| getBarChartOptions () { |
| return { responsive: true } |
| }, |
| getUsageTypeBarChartData () { |
| const datasets = [] |
| for (const row of this.dataSource) { |
| datasets.push({ |
| label: this.$t(row.name), |
| data: [row.quota], |
| ...this.getColor(row) |
| }) |
| } |
| return { labels: [this.$t('label.quota.type.name')], datasets } |
| }, |
| getResourceBarChartData () { |
| const datasets = [] |
| for (const row of this.dataSourceResource) { |
| datasets.push({ |
| label: row.displayname, |
| data: [row.quotaconsumed], |
| ...this.getColor(row) |
| }) |
| } |
| return { labels: [this.$t('label.resource')], datasets } |
| }, |
| getTariffsBarChartData () { |
| const aggregatedTariffs = this.aggregateTariffQuotas() |
| const datasets = [] |
| for (const key in aggregatedTariffs) { |
| datasets.push({ |
| label: key, |
| data: [aggregatedTariffs[key]], |
| ...this.getColor({ tariffname: key }) |
| }) |
| } |
| return { labels: [this.$t('label.quota.tariff')], datasets } |
| }, |
| aggregateTariffQuotas () { |
| const tariffs = {} |
| for (const row of this.dataSourceTariffs) { |
| const currentValue = tariffs[row.tariffname] ?? 0 |
| tariffs[row.tariffname] = currentValue + row.quotaconsumed |
| } |
| return tariffs |
| }, |
| setUsageTypeLineChartData () { |
| this.usageLineChartLabels = this.getLineChartLabelsForData(this.dataSource) |
| this.usageLineChartData = this.prepareLineChartData(this.dataSource, this.usageLineChartLabels) |
| }, |
| setResourceLineChartData () { |
| this.resourceLineChartLabels = this.getLineChartLabelsForData(this.dataSourceResource) |
| this.resourceLineChartData = this.prepareLineChartData(this.dataSourceResource, this.resourceLineChartLabels) |
| }, |
| setTariffLineChartData () { |
| this.dataSourceTariffs.sort((a, b) => new Date(a.enddate) - new Date(b.enddate)) |
| const usageGroupedByTariffName = this.groupUsageByTariffName() |
| |
| const transformedData = Object.values(usageGroupedByTariffName) |
| this.tariffLineChartLabels = this.getLineChartLabelsForData(transformedData) |
| this.tariffLineChartData = this.prepareLineChartData(transformedData, this.tariffLineChartLabels) |
| }, |
| groupUsageByTariffName () { |
| const groupedData = {} |
| this.dataSourceTariffs.forEach((obj) => { |
| if (!(obj.tariffname in groupedData)) { |
| groupedData[obj.tariffname] = { tariffname: obj.tariffname, history: [] } |
| } |
| groupedData[obj.tariffname].history.push(obj) |
| }) |
| return groupedData |
| }, |
| getLineChartLabelForDate (date) { |
| return this.$toLocalDate(date) |
| }, |
| getLineChartLabelsForData (data) { |
| const lineChartLabels = [this.getLineChartLabelForDate(this.startDate)] |
| |
| for (const row of data) { |
| let isPreviousZero = true |
| for (let i = 0; i < row.history.length; i++) { |
| const item = row.history[i] |
| const isCurrentZero = item.quotaconsumed === 0 |
| |
| if (isCurrentZero && isPreviousZero) { |
| continue |
| } |
| |
| if (isPreviousZero) { |
| // Previous was zero, but we current is not. Push our startdate to have an accurate curve |
| this.pushDateToLabelsIfNotPresent(lineChartLabels, this.getLineChartLabelForDate(item.startdate)) |
| } |
| |
| this.pushDateToLabelsIfNotPresent(lineChartLabels, this.getLineChartLabelForDate(item.enddate)) |
| isPreviousZero = isCurrentZero |
| } |
| } |
| |
| lineChartLabels.sort((a, b) => new Date(a) - new Date(b)) |
| return lineChartLabels |
| }, |
| pushDateToLabelsIfNotPresent (lineChartLabels, date) { |
| const hasNearDate = lineChartLabels.some(d => { |
| const diff = Math.abs(new Date(date) - new Date(d).getTime()) |
| return diff < 5 * 1000 * 60 // Do not push the label if there is already one within 5 minutes |
| }) |
| if (!hasNearDate) { |
| lineChartLabels.push(date) |
| return true |
| } |
| return false |
| }, |
| calculatePaddedMax (values) { |
| return Math.ceil(Math.max(...values) * 1.2) |
| }, |
| getChartDataMaxValues (chartData) { |
| return Object.values(chartData).map(item => Math.max(...item.data.map(obj => obj.stat))) |
| }, |
| setYAxisMaxForUsageTypes () { |
| this.YAxisMax.usageTypes = { |
| incremental: this.calculatePaddedMax(this.getChartDataMaxValues(this.usageLineChartData.incremental)), |
| history: this.calculatePaddedMax(this.getChartDataMaxValues(this.usageLineChartData.history)) |
| } |
| }, |
| setYAxisMaxForResources () { |
| this.YAxisMax.resources = { |
| incremental: this.calculatePaddedMax(this.getChartDataMaxValues(this.resourceLineChartData.incremental)), |
| history: this.calculatePaddedMax(this.getChartDataMaxValues(this.resourceLineChartData.history)) |
| } |
| }, |
| setYAxisMaxForTariffs () { |
| this.YAxisMax.tariffs = { |
| incremental: this.calculatePaddedMax(this.getChartDataMaxValues(this.tariffLineChartData.incremental)), |
| history: this.calculatePaddedMax(this.getChartDataMaxValues(this.tariffLineChartData.history)) |
| } |
| }, |
| getEntryForCurrentGraphType (data) { |
| if (this.graphType === 'line_chart') { |
| return data.history |
| } |
| return data.incremental |
| }, |
| prepareDataForUsageTypeLineGraph () { |
| this.setUsageTypeLineChartData() |
| this.setYAxisMaxForUsageTypes() |
| }, |
| prepareDataForResourceLineGraph () { |
| this.setResourceLineChartData() |
| this.setYAxisMaxForResources() |
| }, |
| prepareDataForTariffLineGraph () { |
| this.setTariffLineChartData() |
| this.setYAxisMaxForTariffs() |
| }, |
| prepareLineChartData (data, lineChartLabels) { |
| const chartData = { history: [], incremental: [] } |
| |
| for (const row of data) { |
| const datasetName = this.$t(this.getName(row)) |
| const color = this.getColor(row) |
| |
| const historyDataset = { label: datasetName, data: [], fill: false, ...color } |
| const incrementalDataset = { label: datasetName, data: [], fill: false, ...color } |
| |
| let historyIndex = 0 |
| let accumulatedQuota = 0 |
| |
| for (const label of lineChartLabels) { |
| const periodQuota = this.calculateQuotaForPeriod(row.history, label, historyIndex) |
| historyIndex = periodQuota.nextIndex |
| |
| accumulatedQuota += periodQuota.value |
| historyDataset.data.push({ stat: periodQuota.value }) |
| incrementalDataset.data.push({ stat: accumulatedQuota }) |
| } |
| |
| chartData.history.push(historyDataset) |
| chartData.incremental.push(incrementalDataset) |
| } |
| |
| return chartData |
| }, |
| calculateQuotaForPeriod (historyItems, label, startIndex) { |
| let quota = 0 |
| let currentIndex = startIndex |
| |
| while (currentIndex < historyItems.length) { |
| const item = historyItems[currentIndex] |
| if (this.getLineChartLabelForDate(item.enddate) > label) { |
| break |
| } |
| quota += item.quotaconsumed |
| currentIndex++ |
| } |
| |
| return { value: quota, nextIndex: currentIndex } |
| }, |
| getColor (row) { |
| const quotaType = getQuotaTypeByName(row.name) |
| if (quotaType?.chartColor) { |
| return getChartColorObject(quotaType.chartColor) |
| } |
| return getChartColorObject(this.textToDeterministicColor(this.getName(row))) |
| }, |
| textToDeterministicColor (text) { |
| let hash = 0 |
| |
| for (let i = text.length - 1; i >= 0; i--) { |
| hash = ((hash << 5) - hash) + text.charCodeAt(i) |
| hash = hash & hash |
| } |
| |
| const hash1 = Math.abs(hash) |
| const hash2 = Math.abs(hash * 73) |
| const hash3 = Math.abs(hash * 97) |
| |
| let color = '#' |
| color += (hash1 & 0xFF).toString(16).padStart(2, '0') |
| color += (hash2 & 0xFF).toString(16).padStart(2, '0') |
| color += (hash3 & 0xFF).toString(16).padStart(2, '0') |
| |
| return color |
| }, |
| getName (row) { |
| if (row.name) { |
| // Translate the usage type's name |
| return this.$t(row.name) |
| } |
| return row.displayname || row.tariffname |
| }, |
| getYAxisIncrement (max) { |
| if (max < 1) { |
| return 1 |
| } |
| return Math.pow(10, Math.floor(Math.log10(max))) |
| }, |
| exportDataToCsv () { |
| downloadDataAsCsv({ |
| data: this.dataSource, |
| keys: ['type', 'name', 'unit', 'quota'], |
| fileName: `quota-usage-of-account-${this.$route.params.id}-between-${this.startDate}-and-${this.endDate}` |
| }) |
| }, |
| exportResourcesToCsv () { |
| downloadDataAsCsv({ |
| data: this.dataSourceResource.map(row => ({ ...row, name: row.displayname })), |
| keys: ['resourceid', 'name', 'quotaconsumed'], |
| fileName: `quota-usage-of-resources-of-type-${this.selectedType}-of-account-${this.$route.params.id}-between-${this.startDate}-and-${this.endDate}` |
| }) |
| }, |
| exportResourceDetailsToCsv () { |
| downloadDataAsCsv({ |
| data: this.dataSourceTariffs, |
| keys: ['tariffid', 'tariffname', 'startdate', 'enddate', 'quotaconsumed'], |
| fileName: `detailed-quota-usage-of-resource-${this.selectedResource}-of-type-${this.selectedType}-of-account-${this.$route.params.id}-between-${this.startDate}-and-${this.endDate}` |
| }) |
| }, |
| getQuotaTypesFiltered () { |
| const quotaTypesRetrieved = this.dataSource.map(item => item.name) |
| return getQuotaTypes().filter((item) => quotaTypesRetrieved.includes(item.type)) |
| }, |
| getResources () { |
| return this.dataSourceResource.filter(item => item.resourceid).map(item => ({ id: item.resourceid, name: item.displayname })) |
| }, |
| async handleSelectedTypeChange (value) { |
| this.selectedType = value |
| this.selectedResource = '' |
| this.dataSourceTariffs = [] |
| document.getElementById('resource-by-type').scrollIntoView({ behavior: 'smooth' }) |
| await this.fetchResourceData() |
| }, |
| async handleSelectedResourceChange (value) { |
| this.selectedResource = value |
| document.getElementById('details-by-resource').scrollIntoView({ behavior: 'smooth' }) |
| await this.fetchTariffData() |
| } |
| } |
| } |
| </script> |
| |
| <style lang="scss" scoped> |
| @import '@/style/common/common.scss'; |
| </style> |