This commit is contained in:
2022-03-03 17:55:19 +00:00
parent 089f5d82e4
commit e8d58ad834
13 changed files with 815 additions and 110 deletions

View File

@@ -31,7 +31,7 @@ FIRST CLIENT SOURCE CODE COMMIT JAN 3rd 2019
# SEEDING ISSUES
??seeder wo created date not set properly, should match the way it's generated
seeder, make a few wo that are not completed in time in each month
seeder make reminders and reviews for all users, just random scattering for now to future month ahead at least one per day to show off schedule and widgets
seeder wo need new fields and generate data to show off and test kpi widgets and features
@@ -45,84 +45,50 @@ seeder wo need new fields and generate data to show off and test kpi widgets and
# WIDGETS
https://www.calculator.net/percent-calculator.html
Should LIST types have a fixed limit of maximum records returned??
i.e. no more than 500 or something?
if reaches the limit then says "500 limit reached" in the list as the last item?
- Widgets to make for beta in order of priority
**MUST HAVE***
BAR % wo completed status vs not completed by completed date within interval
query is
all wo not completed that should be by now within the interval vs all that were completed within the interval, count up each, count up the total and present as a pct for that interval
count of wo with complete by in the interval and not closed / count of wo with complete by within the interval and closed
group by convert completed or not into a simple bool so group by completed then by interval like the multiple techs ones as a framework
criteria:
timespan, interval
tags wo
SELECT COUNT(AWORKORDER.ID) Y,
DATE_TRUNC('month',AWORKORDER.createddate) X,
(LASTSTATUSID IS NULL OR AWORKORDERSTATUS.COMPLETED = FALSE) Z
FROM AWORKORDER
LEFT JOIN AWORKORDERSTATUS ON (AWORKORDER.LASTSTATUSID = AWORKORDERSTATUS.ID)
where AWORKORDER.COMPLETEBYDATE < NOW()
GROUP BY X,Z
ORDER BY X ASC
with subq as (
SELECT COUNT(AWORKORDER.ID) wocount,
DATE_TRUNC('month',AWORKORDER.createddate) x,
(LASTSTATUSID IS NULL OR AWORKORDERSTATUS.COMPLETED = FALSE) z
FROM AWORKORDER
LEFT JOIN AWORKORDERSTATUS ON (AWORKORDER.LASTSTATUSID = AWORKORDERSTATUS.ID)
where AWORKORDER.COMPLETEBYDATE < NOW()
GROUP BY x,z
)
select X,Z,
wocount / sum(wocount) over (partition by X) * 100 as Y
from subq
order by x ASC;
...
WITH SUBQ AS
(SELECT COUNT(AWORKORDER.ID) WOCOUNT,
DATE_TRUNC('month', AWORKORDER.CREATEDDATE) X,
(aworkorder.laststatusid is not null AND AWORKORDERSTATUS.COMPLETED = TRUE AND laststate.created < aworkorder.completebydate) Z
FROM AWORKORDER
LEFT JOIN AWORKORDERSTATUS ON (AWORKORDER.LASTSTATUSID = AWORKORDERSTATUS.ID)
LEFT JOIN LATERAL
(SELECT created
FROM aworkorderstate
WHERE aworkorderstate.workorderid = aworkorder.id
ORDER BY aworkorderstate.created DESC
LIMIT 1) AS laststate ON TRUE
WHERE AWORKORDER.COMPLETEBYDATE < NOW()
AND AWORKORDER.CREATEDDATE > '1753-01-02T08:00:59.9990000Z'
AND AWORKORDER.CREATEDDATE < '2022-03-03T01:00:00.0000000Z'
GROUP BY X,Z)
SELECT X,Z,
ROUND(WOCOUNT / SUM(WOCOUNT) OVER (PARTITION BY X) * 100,2) AS Y
FROM SUBQ
ORDER BY X ASC
...
BAR-VERT Billable hours leader board case 3696: https://www.openfaas.com/blog/serverless-single-page-app/?utm_source=DigitalOcean_Newsletter
criteria:
timespan, interval
tags wo
BAR Count of wo within each status by time period / tags
shows all status types that are in the data returned only, not *all* status though I think it does that automatically
future: click on status bar it opens a filtered list of all wo by that status
SELECT COUNT(AWORKORDER.ID) Y,DATE_TRUNC('month', AWORKORDER.createddate) X, aworkorder.laststatusid Z
FROM AWORKORDER
LEFT JOIN AWORKORDERSTATUS ON (AWORKORDER.LASTSTATUSID = AWORKORDERSTATUS.ID)
WHERE AWORKORDER.createddate >'2022-01-01T07:59:59.9990000Z' AND AWORKORDER.createddate <'2023-01-01T08:00:00.0000000Z'
GROUP BY Z, X
ORDER BY X ASC
LIST work orders by status (case 1974)
BAR same as above?? but by % wo within each status by time range / tags
this will show the state of things overall
WITH SUBQ AS
(SELECT COUNT(AWORKORDER.ID) WOCOUNT, DATE_TRUNC('month', AWORKORDER.CREATEDDATE) X,
AWORKORDER.LASTSTATUSID Z
FROM AWORKORDER
LEFT JOIN AWORKORDERSTATUS ON (AWORKORDER.LASTSTATUSID = AWORKORDERSTATUS.ID)
WHERE AWORKORDER.CREATEDDATE > '2022-01-01T07:59:59.9990000Z'
AND AWORKORDER.CREATEDDATE < '2023-01-01T08:00:00.0000000Z'
GROUP BY Z, X)
SELECT X,Z,
ROUND(WOCOUNT / SUM(WOCOUNT) OVER (PARTITION BY X) * 100,2) AS Y
FROM SUBQ
ORDER BY X ASC, y desc
LIST work orders by status (case 1974)
this *does* make sense because it can be hyper specific to something like a "waiting for parts" status so
if that is useful to a user then can see that list
needs limit, could bring in thousands if not careful
criteria:
wo status
timespan
@@ -132,13 +98,12 @@ ORDER BY X ASC
**NICE TO HAVE**
(these are not triaged yet)
DASHBOARD:CR - open wo list by selectable status case 1974
avg time or time breakdown by % of overdueness of workorders
i.e. 10% of overdue were x days overdue etc
avg time in each status by time period / tags
this could cover response time as they can just designate a status as unresponded or new
% wo within each status by time range / tags
this will show the state of things overall
@@ -930,6 +895,9 @@ BUILD 8.0.0-beta.1-rc3 CHANGES OF NOTE
- added dashboard widget Service rate quantity showing personal service rate quantity on chart as line or bar version
- added dashboard widget Service rate quantity - All showing all selected criteria users service rate quantity on chart as line or bar version
- added dashboard widget Count of work orders created per day over time as bar and line chart for management
- added dashboard widget % of work orders completed on time as bar chart for management
- TODO: statuscount
- TODO: status pct
- Added *back* User color as it now ties in with widget charts (user edit form, import, backend, docs etc)
- v8-migrate plugin, fixed new issue related to removal of unused locale / translation keys preventing migrate
- Login form added prominent warning "beta test - not for production use"

View File

@@ -5,6 +5,48 @@ const role = authorizationroles.AUTHORIZATION_ROLES;
*/
export default {
registry: [
{
roles: [
role.BizAdmin,
role.BizAdminRestricted,
role.ServiceRestricted,
role.Service,
role.Accounting
],
title: "DashboardWorkOrderStatusCount",
icon: "$ayiChartBar",
type: "GzDashWorkOrderStatusCount",
scheduleableUserOnly: false,
singleOnly: false,
settings: {
customTitle: null,
timeSpan: "*thisyear*",
interval: "month",
wotags: [],
wotagsany: true
}
},
{
roles: [
role.BizAdmin,
role.BizAdminRestricted,
role.ServiceRestricted,
role.Service,
role.Accounting
],
title: "DashboardWorkOrderStatusPct",
icon: "$ayiChartBar",
type: "GzDashWorkOrderStatusPct",
scheduleableUserOnly: false,
singleOnly: false,
settings: {
customTitle: null,
timeSpan: "*thisyear*",
interval: "month",
wotags: [],
wotagsany: true
}
},
{
roles: [
role.BizAdmin,

View File

@@ -222,8 +222,6 @@ export default {
await initWidget(this);
},
async mounted() {
//must be called from mounted to have refs available
//console.log("reminders-mounted");
await this.getDataFromApi();
},
methods: {

View File

@@ -225,8 +225,6 @@ export default {
await initWidget(this);
},
async mounted() {
//must be called from mounted to have refs available
//console.log("reminders-mounted");
await this.getDataFromApi();
},
methods: {

View File

@@ -195,8 +195,6 @@ export default {
await initWidget(this);
},
async mounted() {
//must be called from mounted to have refs available
//console.log("reminders-mounted");
await this.getDataFromApi();
},
methods: {

View File

@@ -198,8 +198,6 @@ export default {
await initWidget(this);
},
async mounted() {
//must be called from mounted to have refs available
//console.log("reminders-mounted");
await this.getDataFromApi();
},
methods: {

View File

@@ -74,8 +74,6 @@ export default {
//console.log("reminders-beforeUpdate");
},
async mounted() {
//must be called from mounted to have refs available
//console.log("reminders-mounted");
await this.getDataFromApi();
},
methods: {

View File

@@ -164,25 +164,6 @@ export default {
},
computed: {
chartData() {
// let onTime = {
// lable: "Ontime",
// backgroundColor: "#00ff00",
// data: []
// };
// let notOnTime = {
// lable: "Not on time",
// backgroundColor: "#ff0000",
// data: []
// };
// this.obj.forEach(z => {
// if (z.z) {
// notOnTime.data.push({ x: z.x, y: z.y });
// } else {
// onTime.data.push({ x: z.x, y: z.y });
// }
// });
// return { datasets: [onTime, notOnTime] };
let onTime = {
backgroundColor: this.settings.color,
data: []
@@ -201,8 +182,6 @@ export default {
await initWidget(this);
},
async mounted() {
//must be called from mounted to have refs available
//console.log("reminders-mounted");
await this.getDataFromApi();
},
methods: {

View File

@@ -195,8 +195,6 @@ export default {
await initWidget(this);
},
async mounted() {
//must be called from mounted to have refs available
//console.log("reminders-mounted");
await this.getDataFromApi();
},
methods: {

View File

@@ -198,8 +198,6 @@ export default {
await initWidget(this);
},
async mounted() {
//must be called from mounted to have refs available
//console.log("reminders-mounted");
await this.getDataFromApi();
},
methods: {

View File

@@ -0,0 +1,362 @@
<template>
<gz-dash
icon="$ayiUser"
:show-context-button="true"
:update-frequency="900000"
v-bind="[$props, $attrs]"
@dash-refresh="getDataFromApi()"
@dash-context="showContext()"
v-on="$listeners"
>
<template slot="main">
<v-sheet
v-if="obj.length == 0"
height="400"
class="ml-6 mt-6 text-h4 grey--text text--lighten-1"
>
{{ $ay.t("NoData") }}
</v-sheet>
<gz-chart-bar v-else :chart-data="chartData" :options="chartOptions" />
</template>
<template slot="settings">
<div></div>
<v-col v-if="context" cols="12">
<v-dialog
v-model="context"
scrollable
max-width="400px"
data-cy="dashSettings"
@keydown.esc="cancel"
>
<v-card elevation="24">
<v-card-title class="text-h5 lighten-2" primary-title>
<span> {{ $ay.t("Settings") }} </span>
</v-card-title>
<v-card-text>
<v-select
v-model="localSettings.timeSpan"
class="mt-4"
:items="selectLists.dateFilterTokens"
item-text="name"
item-value="id"
:label="$ay.t('TimeSpan')"
></v-select>
<v-select
v-model="localSettings.interval"
class="mt-4"
:items="selectLists.units"
item-text="name"
item-value="id"
:label="$ay.t('Interval')"
></v-select>
<gz-tag-picker
v-model="localSettings.wotags"
class="mt-4"
:label="$ay.t('Tags') + ' - ' + $ay.t('WorkOrder')"
></gz-tag-picker>
<v-radio-group
v-if="localSettings.wotags.length > 1"
v-model="localSettings.wotagsany"
row
class="mt-n3"
>
<v-radio
:label="$ay.t('GridFilterDialogAndRadioText')"
:value="false"
></v-radio>
<v-radio
:label="$ay.t('GridFilterDialogOrRadioText')"
:value="true"
></v-radio>
</v-radio-group>
<v-text-field
v-model="localSettings.customTitle"
class="mt-4"
:label="$ay.t('Name')"
></v-text-field>
</v-card-text>
<v-divider></v-divider>
<v-card-actions>
<v-btn color="primary" text @click.native="context = false">{{
$ay.t("Cancel")
}}</v-btn>
<v-spacer></v-spacer>
<v-btn
color="primary"
text
class="ml-4"
@click="updateSettings"
>{{ $ay.t("Save") }}</v-btn
>
</v-card-actions>
</v-card>
</v-dialog>
</v-col>
</template>
</gz-dash>
</template>
<script>
import GzDash from "./dash-base.vue";
export default {
components: {
GzDash
},
props: {
settings: { type: Object, default: null }
},
data() {
return {
obj: {},
meta: [],
context: false,
localSettings: {},
selectLists: {
dateFilterTokens: [],
units: []
},
chartOptions: {
responsive: true,
maintainAspectRatio: false,
scales: {
xAxes: [
{
type: "time",
time: {
unit: "day"
},
gridLines: {
drawOnChartArea: false
},
offset: true
}
],
yAxes: [
{
gridLines: {
drawOnChartArea: false
},
ticks: {
beginAtZero: true
}
}
]
}
}
};
},
computed: {
chartData() {
let ret = [];
this.meta.forEach(m => {
let statusData = this.obj.filter(d => d.z == m.id);
if (statusData.length > 0) {
ret.push({
label: m.name,
backgroundColor: m.color,
data: statusData.map(d => {
return { x: d.x, y: d.y };
})
});
}
});
return { datasets: ret };
}
},
async created() {
await initWidget(this);
},
async mounted() {
await this.getDataFromApi();
},
methods: {
showContext: function() {
this.localSettings = window.$gz.util.deepCopySkip(this.settings);
this.context = true;
},
updateSettings: function() {
//copy settings from local to parent settings, need to do it this way or get error about mutating prop directly which is vexing and has no easy solution seemingly
this.settings.customTitle = this.localSettings.customTitle;
this.settings.timeSpan = this.localSettings.timeSpan;
this.settings.interval = this.localSettings.interval;
this.settings.wotags = this.localSettings.wotags;
this.settings.wotagsany = this.localSettings.wotagsany;
this.$emit("dash-change"); //trigger save to server
this.context = false;
this.getDataFromApi();
},
async getDataFromApi() {
try {
this.errorMessage = null;
const res = await window.$gz.api.post("kpi", {
KPIName: "WorkOrderStatusCount",
criteria: {
timeSpan: this.settings.timeSpan,
interval: this.settings.interval,
wotags: this.settings.wotags,
wotagsany: this.settings.wotagsany
},
clientTimeStamp: window.$gz.locale.clientLocalZoneTimeStamp()
});
if (res.error) {
this.errorMessage = res.error;
} else {
this.chartOptions.scales.xAxes[0].time.unit = this.settings.interval;
res.data.forEach(z => {
z.x = new Date(z.x) //convert to locale timezone and output in the closest thing to iso-8601 format
.toLocaleString("sv-SE", {
timeZone: this.timeZoneName
});
});
this.meta = res.meta;
this.meta.unshift({
id: null,
name: "---",
color: "#eeeeee"
});
this.obj = res.data;
}
} catch (error) {
this.errorMessage = error.toString();
}
}
}
};
/////////////////////////////////
//
//
async function initWidget(vm) {
await fetchTranslatedText();
populateSelectionLists(vm);
}
//////////////////////////////////////////////////////////
//
// Ensures UI translated text is available
//
async function fetchTranslatedText() {
await window.$gz.translation.cacheTranslations([
"Filter",
"DateRangeYesterday",
"DateRangeToday",
"DateRangeLastWeek",
"DateRangeThisWeek",
"DateRangeNextWeek",
"DateRangeLastMonth",
"DateRangeThisMonth",
"DateRangeNextMonth",
"DateRange14DayWindow",
"DateRangePast",
"DateRangeLastYear",
"DateRangeThisYear",
"DateRangeInTheLastThreeMonths",
"DateRangeInTheLastSixMonths",
"DateRangePastYear",
"DateRangePast90Days",
"DateRangePast30Days",
"DateRangePast7Days",
"DateRangePast24Hours",
"DateRangePast6Hours",
"DateRangeJanuary",
"DateRangeFebruary",
"DateRangeMarch",
"DateRangeApril",
"DateRangeMay",
"DateRangeJune",
"DateRangeJuly",
"DateRangeAugust",
"DateRangeSeptember",
"DateRangeOctober",
"DateRangeNovember",
"DateRangeDecember",
"DateRangePreviousYearThisMonth",
"DateRangePreviousYearLastMonth",
"DateRangePreviousYearNextMonth",
"TimeSpanDays",
"TimeSpanMonths",
"Name",
"TimeSpan",
"Interval",
"WorkOrder",
"GridFilterDialogAndRadioText",
"GridFilterDialogOrRadioText"
]);
}
/////////////////////////////////
//
//
function populateSelectionLists(vm) {
vm.selectLists.dateFilterTokens.push(
...[
// { name: vm.$ay.t("DateRangeYesterday"), id: "*yesterday*" },
// { name: vm.$ay.t("DateRangeToday"), id: "*today*" },
{ name: vm.$ay.t("DateRangeThisYear"), id: "*thisyear*" },
{ name: vm.$ay.t("DateRangeThisMonth"), id: "*thismonth*" },
{ name: vm.$ay.t("DateRangeThisWeek"), id: "*thisweek*" },
{ name: vm.$ay.t("DateRangeLastYear"), id: "*lastyear*" }, //prior year from jan to dec
{ name: vm.$ay.t("DateRangeLastMonth"), id: "*lastmonth*" },
{ name: vm.$ay.t("DateRangeLastWeek"), id: "*lastweek*" },
//-------------------------- rando ones -------------------
{ name: vm.$ay.t("DateRange14DayWindow"), id: "*14daywindow*" },
{ name: vm.$ay.t("DateRangePast"), id: "*past*" },
{
name: vm.$ay.t("DateRangeInTheLastThreeMonths"),
id: "*last3months*"
},
{
name: vm.$ay.t("DateRangeInTheLastSixMonths"),
id: "*last6months*"
},
{ name: vm.$ay.t("DateRangePastYear"), id: "*pastyear*" }, //last 365 days
{ name: vm.$ay.t("DateRangePast90Days"), id: "*past90days*" },
{ name: vm.$ay.t("DateRangePast30Days"), id: "*past30days*" },
{ name: vm.$ay.t("DateRangePast7Days"), id: "*past7days*" },
// { name: vm.$ay.t("DateRangePast24Hours"), id: "*past24hours*" },
// { name: vm.$ay.t("DateRangePast6Hours"), id: "*past6hours*" },
{ name: vm.$ay.t("DateRangeJanuary"), id: "*january*" },
{ name: vm.$ay.t("DateRangeFebruary"), id: "*february*" },
{ name: vm.$ay.t("DateRangeMarch"), id: "*march*" },
{ name: vm.$ay.t("DateRangeApril"), id: "*april*" },
{ name: vm.$ay.t("DateRangeMay"), id: "*may*" },
{ name: vm.$ay.t("DateRangeJune"), id: "*june*" },
{ name: vm.$ay.t("DateRangeJuly"), id: "*july*" },
{ name: vm.$ay.t("DateRangeAugust"), id: "*august*" },
{ name: vm.$ay.t("DateRangeSeptember"), id: "*september*" },
{ name: vm.$ay.t("DateRangeOctober"), id: "*october*" },
{ name: vm.$ay.t("DateRangeNovember"), id: "*november*" },
{ name: vm.$ay.t("DateRangeDecember"), id: "*december*" },
{
name: vm.$ay.t("DateRangePreviousYearThisMonth"),
id: "*lastyearthismonth*"
},
{
name: vm.$ay.t("DateRangePreviousYearLastMonth"),
id: "*lastyearlastmonth*"
},
{
name: vm.$ay.t("DateRangePreviousYearNextMonth"),
id: "*lastyearnextmonth*"
}
]
);
vm.selectLists.units.push(
...[
{ name: vm.$ay.t("TimeSpanDays"), id: "day" },
{
name: vm.$ay.t("TimeSpanMonths"),
id: "month"
}
]
);
}
</script>

View File

@@ -0,0 +1,364 @@
<template>
<gz-dash
icon="$ayiUser"
:show-context-button="true"
:update-frequency="900000"
v-bind="[$props, $attrs]"
@dash-refresh="getDataFromApi()"
@dash-context="showContext()"
v-on="$listeners"
>
<template slot="main">
<v-sheet
v-if="obj.length == 0"
height="400"
class="ml-6 mt-6 text-h4 grey--text text--lighten-1"
>
{{ $ay.t("NoData") }}
</v-sheet>
<gz-chart-bar v-else :chart-data="chartData" :options="chartOptions" />
</template>
<template slot="settings">
<div></div>
<v-col v-if="context" cols="12">
<v-dialog
v-model="context"
scrollable
max-width="400px"
data-cy="dashSettings"
@keydown.esc="cancel"
>
<v-card elevation="24">
<v-card-title class="text-h5 lighten-2" primary-title>
<span> {{ $ay.t("Settings") }} </span>
</v-card-title>
<v-card-text>
<v-select
v-model="localSettings.timeSpan"
class="mt-4"
:items="selectLists.dateFilterTokens"
item-text="name"
item-value="id"
:label="$ay.t('TimeSpan')"
></v-select>
<v-select
v-model="localSettings.interval"
class="mt-4"
:items="selectLists.units"
item-text="name"
item-value="id"
:label="$ay.t('Interval')"
></v-select>
<gz-tag-picker
v-model="localSettings.wotags"
class="mt-4"
:label="$ay.t('Tags') + ' - ' + $ay.t('WorkOrder')"
></gz-tag-picker>
<v-radio-group
v-if="localSettings.wotags.length > 1"
v-model="localSettings.wotagsany"
row
class="mt-n3"
>
<v-radio
:label="$ay.t('GridFilterDialogAndRadioText')"
:value="false"
></v-radio>
<v-radio
:label="$ay.t('GridFilterDialogOrRadioText')"
:value="true"
></v-radio>
</v-radio-group>
<v-text-field
v-model="localSettings.customTitle"
class="mt-4"
:label="$ay.t('Name')"
></v-text-field>
</v-card-text>
<v-divider></v-divider>
<v-card-actions>
<v-btn color="primary" text @click.native="context = false">{{
$ay.t("Cancel")
}}</v-btn>
<v-spacer></v-spacer>
<v-btn
color="primary"
text
class="ml-4"
@click="updateSettings"
>{{ $ay.t("Save") }}</v-btn
>
</v-card-actions>
</v-card>
</v-dialog>
</v-col>
</template>
</gz-dash>
</template>
<script>
import GzDash from "./dash-base.vue";
export default {
components: {
GzDash
},
props: {
settings: { type: Object, default: null }
},
data() {
return {
obj: {},
meta: [],
context: false,
localSettings: {},
selectLists: {
dateFilterTokens: [],
units: []
},
chartOptions: {
responsive: true,
maintainAspectRatio: false,
scales: {
xAxes: [
{
type: "time",
time: {
unit: "day"
},
gridLines: {
drawOnChartArea: false
},
offset: true
}
],
yAxes: [
{
gridLines: {
drawOnChartArea: false
},
ticks: {
beginAtZero: true,
min: 0,
max: 100
}
}
]
}
}
};
},
computed: {
chartData() {
let ret = [];
this.meta.forEach(m => {
let statusData = this.obj.filter(d => d.z == m.id);
if (statusData.length > 0) {
ret.push({
label: m.name,
backgroundColor: m.color,
data: statusData.map(d => {
return { x: d.x, y: d.y };
})
});
}
});
return { datasets: ret };
}
},
async created() {
await initWidget(this);
},
async mounted() {
await this.getDataFromApi();
},
methods: {
showContext: function() {
this.localSettings = window.$gz.util.deepCopySkip(this.settings);
this.context = true;
},
updateSettings: function() {
//copy settings from local to parent settings, need to do it this way or get error about mutating prop directly which is vexing and has no easy solution seemingly
this.settings.customTitle = this.localSettings.customTitle;
this.settings.timeSpan = this.localSettings.timeSpan;
this.settings.interval = this.localSettings.interval;
this.settings.wotags = this.localSettings.wotags;
this.settings.wotagsany = this.localSettings.wotagsany;
this.$emit("dash-change"); //trigger save to server
this.context = false;
this.getDataFromApi();
},
async getDataFromApi() {
try {
this.errorMessage = null;
const res = await window.$gz.api.post("kpi", {
KPIName: "WorkOrderStatusPct",
criteria: {
timeSpan: this.settings.timeSpan,
interval: this.settings.interval,
wotags: this.settings.wotags,
wotagsany: this.settings.wotagsany
},
clientTimeStamp: window.$gz.locale.clientLocalZoneTimeStamp()
});
if (res.error) {
this.errorMessage = res.error;
} else {
this.chartOptions.scales.xAxes[0].time.unit = this.settings.interval;
res.data.forEach(z => {
z.x = new Date(z.x) //convert to locale timezone and output in the closest thing to iso-8601 format
.toLocaleString("sv-SE", {
timeZone: this.timeZoneName
});
});
this.meta = res.meta;
this.meta.unshift({
id: null,
name: "---",
color: "#eeeeee"
});
this.obj = res.data;
}
} catch (error) {
this.errorMessage = error.toString();
}
}
}
};
/////////////////////////////////
//
//
async function initWidget(vm) {
await fetchTranslatedText();
populateSelectionLists(vm);
}
//////////////////////////////////////////////////////////
//
// Ensures UI translated text is available
//
async function fetchTranslatedText() {
await window.$gz.translation.cacheTranslations([
"Filter",
"DateRangeYesterday",
"DateRangeToday",
"DateRangeLastWeek",
"DateRangeThisWeek",
"DateRangeNextWeek",
"DateRangeLastMonth",
"DateRangeThisMonth",
"DateRangeNextMonth",
"DateRange14DayWindow",
"DateRangePast",
"DateRangeLastYear",
"DateRangeThisYear",
"DateRangeInTheLastThreeMonths",
"DateRangeInTheLastSixMonths",
"DateRangePastYear",
"DateRangePast90Days",
"DateRangePast30Days",
"DateRangePast7Days",
"DateRangePast24Hours",
"DateRangePast6Hours",
"DateRangeJanuary",
"DateRangeFebruary",
"DateRangeMarch",
"DateRangeApril",
"DateRangeMay",
"DateRangeJune",
"DateRangeJuly",
"DateRangeAugust",
"DateRangeSeptember",
"DateRangeOctober",
"DateRangeNovember",
"DateRangeDecember",
"DateRangePreviousYearThisMonth",
"DateRangePreviousYearLastMonth",
"DateRangePreviousYearNextMonth",
"TimeSpanDays",
"TimeSpanMonths",
"Name",
"TimeSpan",
"Interval",
"WorkOrder",
"GridFilterDialogAndRadioText",
"GridFilterDialogOrRadioText"
]);
}
/////////////////////////////////
//
//
function populateSelectionLists(vm) {
vm.selectLists.dateFilterTokens.push(
...[
// { name: vm.$ay.t("DateRangeYesterday"), id: "*yesterday*" },
// { name: vm.$ay.t("DateRangeToday"), id: "*today*" },
{ name: vm.$ay.t("DateRangeThisYear"), id: "*thisyear*" },
{ name: vm.$ay.t("DateRangeThisMonth"), id: "*thismonth*" },
{ name: vm.$ay.t("DateRangeThisWeek"), id: "*thisweek*" },
{ name: vm.$ay.t("DateRangeLastYear"), id: "*lastyear*" }, //prior year from jan to dec
{ name: vm.$ay.t("DateRangeLastMonth"), id: "*lastmonth*" },
{ name: vm.$ay.t("DateRangeLastWeek"), id: "*lastweek*" },
//-------------------------- rando ones -------------------
{ name: vm.$ay.t("DateRange14DayWindow"), id: "*14daywindow*" },
{ name: vm.$ay.t("DateRangePast"), id: "*past*" },
{
name: vm.$ay.t("DateRangeInTheLastThreeMonths"),
id: "*last3months*"
},
{
name: vm.$ay.t("DateRangeInTheLastSixMonths"),
id: "*last6months*"
},
{ name: vm.$ay.t("DateRangePastYear"), id: "*pastyear*" }, //last 365 days
{ name: vm.$ay.t("DateRangePast90Days"), id: "*past90days*" },
{ name: vm.$ay.t("DateRangePast30Days"), id: "*past30days*" },
{ name: vm.$ay.t("DateRangePast7Days"), id: "*past7days*" },
// { name: vm.$ay.t("DateRangePast24Hours"), id: "*past24hours*" },
// { name: vm.$ay.t("DateRangePast6Hours"), id: "*past6hours*" },
{ name: vm.$ay.t("DateRangeJanuary"), id: "*january*" },
{ name: vm.$ay.t("DateRangeFebruary"), id: "*february*" },
{ name: vm.$ay.t("DateRangeMarch"), id: "*march*" },
{ name: vm.$ay.t("DateRangeApril"), id: "*april*" },
{ name: vm.$ay.t("DateRangeMay"), id: "*may*" },
{ name: vm.$ay.t("DateRangeJune"), id: "*june*" },
{ name: vm.$ay.t("DateRangeJuly"), id: "*july*" },
{ name: vm.$ay.t("DateRangeAugust"), id: "*august*" },
{ name: vm.$ay.t("DateRangeSeptember"), id: "*september*" },
{ name: vm.$ay.t("DateRangeOctober"), id: "*october*" },
{ name: vm.$ay.t("DateRangeNovember"), id: "*november*" },
{ name: vm.$ay.t("DateRangeDecember"), id: "*december*" },
{
name: vm.$ay.t("DateRangePreviousYearThisMonth"),
id: "*lastyearthismonth*"
},
{
name: vm.$ay.t("DateRangePreviousYearLastMonth"),
id: "*lastyearlastmonth*"
},
{
name: vm.$ay.t("DateRangePreviousYearNextMonth"),
id: "*lastyearnextmonth*"
}
]
);
vm.selectLists.units.push(
...[
{ name: vm.$ay.t("TimeSpanDays"), id: "day" },
{
name: vm.$ay.t("TimeSpanMonths"),
id: "month"
}
]
);
}
</script>

View File

@@ -97,6 +97,8 @@ import GzDashWorkorderOverdueAllList from "../components/dash-workorder-overdue-
import GzDashWorkOrderCreatedCountLine from "../components/dash-work-order-created-count-line.vue";
import GzDashWorkOrderCreatedCountBar from "../components/dash-work-order-created-count-bar.vue";
import GzDashPctWorkOrderCompletedOnTimeBar from "../components/dash-work-order-completed-on-time-pct-bar.vue";
import GzDashWorkOrderStatusCount from "../components/dash-work-order-status-count-bar.vue";
import GzDashWorkOrderStatusPct from "../components/dash-work-order-status-pct-bar.vue";
export default {
components: {
GzDashLaborHoursPersonalLine,
@@ -112,7 +114,9 @@ export default {
GzDashWorkorderOverdueAllList,
GzDashWorkOrderCreatedCountLine,
GzDashWorkOrderCreatedCountBar,
GzDashPctWorkOrderCompletedOnTimeBar
GzDashPctWorkOrderCompletedOnTimeBar,
GzDashWorkOrderStatusCount,
GzDashWorkOrderStatusPct
},
data() {
return {