Merged in feature/PMCORE-3300 (pull request #8125)

PMCORE-3300

Approved-by: Henry Jonathan Quispe Quispe
This commit is contained in:
Rodrigo Quelca
2021-09-14 14:05:29 +00:00
committed by Julio Cesar Laura Avendaño
7 changed files with 876 additions and 28 deletions

View File

@@ -0,0 +1,58 @@
import axios from "axios";
import ApiInstance from "./Api.js";
import Services from "./Services";
let Api = new ApiInstance( Services );
export let custom = {
inbox(data) {
let service = "INBOX_CUSTOM_LIST",
keys = {},
params;
keys["id"] = data.id,
params = data.filters;
return Api.post({
service,
data: params,
keys
});
},
draft(data) {
let service = "INBOX_CUSTOM_LIST",
keys = {},
params;
service = "DRAFT_CUSTOM_LIST";
keys["id"] = data.id;
params = data.filters;
return Api.post({
service,
data: params,
keys
});
},
paused(data) {
let service = "INBOX_CUSTOM_LIST",
keys = {},
params;
service = "PAUSED_CUSTOM_LIST";
keys["id"] = data.id;
params = data.filters;
return Api.post({
service,
data: params,
keys
});
},
unassigned(data) {
let service = "INBOX_CUSTOM_LIST",
keys = {},
params;
service = "UNASSIGNED_CUSTOM_LIST";
keys["id"] = data.id;
params = data.filters;
return Api.post({
service,
data: params,
keys
});
}
};

View File

@@ -5,7 +5,7 @@ import { config } from "./Config";
import { caseNotes } from "./CaseNotes";
import { process } from "./Process";
import { filters } from "./Filters";
import { custom } from "./Custom";
export default {
menu,
@@ -14,5 +14,6 @@ export default {
process,
caseNotes,
filters,
config
config,
custom
};

View File

@@ -0,0 +1,361 @@
<template>
<div>
<SearchPopover
target="popover-target-1"
@savePopover="onOk"
:title="addSearchTitle"
>
<template v-slot:body>
<b-form-group>
<b-form-radio-group
v-model="selectedRadio"
:options="getFilterColletion('radio')"
value-field="id"
text-field="optionLabel"
name="flavour-2a"
stacked
></b-form-radio-group>
<b-form-group> </b-form-group>
<b-form-checkbox-group
id="checkbox-1"
v-model="selectedCheckbox"
:options="getFilterColletion('checkbox')"
value-field="id"
text-field="optionLabel"
name="checkbox-1"
>
</b-form-checkbox-group>
</b-form-group>
</template>
</SearchPopover>
<div class="p-1 v-flex">
<h5 class="v-search-title">{{ title }}</h5>
<div class="pm-in-text-icon">
<i :class="icon"></i>
</div>
<b-input-group class="w-75 p-1">
<div class="input-group mb-3">
<div class="input-group-prepend">
<span
class="input-group-text bg-primary-pm text-white"
id="popover-target-1"
@click="searchClickHandler"
>
<b-icon icon="search"></b-icon
></span>
</div>
<b-form-tags input-id="tags-pills" v-model="searchTags">
<template v-slot="{ tags, tagVariant, removeTag }">
<div class="d-inline-block" style="font-size: 1rem">
<b-form-tag
v-for="tag in tags"
@remove="customRemove(removeTag, tag)"
:key="tag"
:title="tag"
:variant="tagVariant"
class="mr-1 badge badge-light"
>
<div :id="tag">
<i class="fas fa-tags"></i>
{{ tagContent(tag) }}
</div>
<component
v-bind:is="tagComponent(tag)"
v-bind:info="tagInfo(tag)"
v-bind:tag="tag"
v-bind:filter="dataToFilter(tag)"
@updateSearchTag="updateSearchTag"
/>
</b-form-tag>
</div>
</template>
</b-form-tags>
</div>
</b-input-group>
</div>
</div>
</template>
<script>
import SearchPopover from "./popovers/SearchPopover.vue";
import CaseNumber from "./popovers/CaseNumber.vue";
import CaseTitle from "./popovers/CaseTitle.vue";
import ProcessName from "./popovers/ProcessName.vue";
import DateFilter from "./popovers/DateFilter.vue";
import TaskTitle from "./popovers/TaskTitle.vue";
import CurrentUser from "./popovers/CurrentUser.vue";
import VARCHAR from "./popovers/String.vue";
import DATETIME from "./popovers/DateTime.vue";
import api from "./../../api/index";
export default {
name: "CustomFilter",
props: ["filters", "title", "icon", "hiddenItems", "filterItems"],
components: {
SearchPopover,
CaseNumber,
CaseTitle,
ProcessName,
DateFilter,
TaskTitle,
CurrentUser,
VARCHAR,
DATETIME
},
data() {
return {
searchLabel: this.$i18n.t("ID_SEARCH"),
addSearchTitle: this.$i18n.t("ID_ADD_SEARCH_FILTER_CRITERIA"),
searchTags: [],
dataLoaded: false,
selectedRadio: "",
selectedCheckbox: [],
itemModel: {},
byProcessName: "",
criteriaItemsRadio: [],
criteriaItemsCheckbox: [],
};
},
watch: {
filters: {
immediate: true,
handler(newVal, oldVal) {
this.searchClickHandler();
this.searchTags = [];
this.selectedRadio = "";
//Prevent show popover at the first time
if (newVal.length) {
this.setFilters(newVal, oldVal);
this.searchClickHandler();
}
},
},
},
methods: {
/**
* Get filter as a collection
* @param {string}
* @returns {object}
*/
getFilterColletion(type) {
let found,
criteria = [],
filterCollection = this.filterItems.filter(
(item) => item.group === type
);
if (this.hiddenItems && this.hiddenItems.length) {
filterCollection.forEach((item) => {
found = this.hiddenItems.find((elem) => elem !== item.id);
if (found) {
criteria.push(item);
}
});
return criteria;
} else {
return filterCollection;
}
},
/**
* Add filter criteria save button handler
*/
onOk() {
let self = this,
element,
initialFilters = [],
item;
this.$root.$emit("bv::hide::popover");
element = _.find(this.filterItems, function(o) {
return o.id === self.selectedRadio;
});
if (element) {
initialFilters = this.prepareFilterItems(
element,
this.selectedRadio,
true
);
}
self.selectedCheckbox.forEach((item) => {
element = _.find(this.filterItems, function(o) {
return o.id === item;
});
if (element) {
initialFilters =[...new Set([...initialFilters,...this.prepareFilterItems(element, item, true)])];
}
});
this.$emit("onUpdateFilters", {
params: initialFilters,
refresh: false,
});
},
/**
* Prepare the filter items
* @param {array} items
* @param {id} string
* @param {boolean} restore
*/
prepareFilterItems(element, id, restore) {
let initialFilters = [],
self = this,
filter,
item;
_.forEach(element.items, function(value, key) {
filter = _.find(self.filters, function(o) {
return o.filterVar === value.id;
});
if (filter && restore) {
initialFilters.push(filter);
} else {
item = {
filterVar: value.id,
type: element.type,
fieldId: id,
value: "",
label: "",
options: [],
autoShow: true,
};
initialFilters.push(item);
}
});
return initialFilters;
},
/**
* Set Filters and make the tag labels
* @param {object} filters json to manage the query
*/
setFilters(filters, oldVal) {
let self = this;
_.forEach(filters, function(item, key) {
let component = _.find(self.filterItems, function(
o
) {
return o.id === item.fieldId;
});
if (component) {
self.searchTags.push(component.id);
self.selectedRadio = component.id;
self.itemModel[component.id] = component;
self.itemModel[component.id].autoShow =
typeof item.autoShow !== "undefined"
? item.autoShow
: true;
}
});
},
/**
* Prepare data filter
* @param {string} id
* @returns {object}
*/
dataToFilter(id) {
let data = [];
_.forEach(this.filters, function(item) {
if (item.fieldId === id) {
data.push(item);
}
});
return data;
},
/**
* Prepare tag content
* @param {string} id
* @returns {string}
*/
tagContent(id) {
if (
this.itemModel[id] &&
typeof this.itemModel[id].makeTagText === "function"
) {
return this.itemModel[id].makeTagText(
this.itemModel[id],
this.dataToFilter(id)
);
}
return "";
},
/**
* Prepare tag component
* @param {string} id
* @returns {string|null}
*/
tagComponent(id) {
if (this.itemModel[id]) {
return this.itemModel[id].type;
}
return null;
},
/**
* Prepare the tag info
* @param {string} id
* @returns {string|null}
*/
tagInfo(id) {
if (this.itemModel[id]) {
return this.itemModel[id];
}
return null;
},
/**
* Remove from tag button
* @param {function} removeTag - default callback
* @param {string} tag filter identifier
*/
customRemove(removeTag, tag) {
let temp = [];
_.forEach(this.filters, function(item, key) {
if (item.fieldId !== tag) {
temp.push(item);
}
});
if (tag === "processName") {
this.byProcessName = "";
}
this.$emit("onUpdateFilters", { params: temp, refresh: true });
},
/**
* Update the filter model this is fired from filter popaver save action
* @param {object} params - arrives the settings
* @param {string} tag filter identifier
*/
updateSearchTag(params) {
let temp = this.filters.concat(params);
temp = [...new Set([...this.filters, ...params])];
this.$emit("onUpdateFilters", { params: temp, refresh: true });
},
/**
* Seach click event handler
*/
searchClickHandler() {
this.$root.$emit("bv::hide::popover");
},
},
};
</script>
<style scoped>
.bv-example-row .row + .row {
margin-top: 1rem;
}
.bv-example-row-flex-cols .row {
min-height: 10rem;
}
.bg-primary-pm {
background-color: #0099dd;
}
.v-flex {
display: flex;
}
.v-search-title {
padding-right: 10px;
line-height: 40px;
}
.pm-in-text-icon {
font-size: 2vw;
padding-right: 10px;
line-height: 3vw;
}
</style>

View File

@@ -0,0 +1,88 @@
<template>
<div id="">
<SearchPopover
:target="tag"
@savePopover="onOk"
:title="info.title"
:autoShow="info.autoShow || false"
>
<template v-slot:body>
<p>{{ info.detail }}</p>
<form ref="form" @submit.stop.prevent="handleSubmit">
<div class="row">
<div class="col">
<b-form-group>
<b-form-datepicker
id="from"
v-model="from"
></b-form-datepicker>
</b-form-group>
</div>
<div class="col">
<b-form-group>
<b-form-datepicker
id="to"
v-model="to"
></b-form-datepicker>
</b-form-group>
</div>
</div>
</form>
</template>
</SearchPopover>
</div>
</template>
<script>
import SearchPopover from "./SearchPopover.vue";
export default {
components: {
SearchPopover,
},
props: ["tag", "info", "filter"],
data() {
return {
from: this.filter[0] ? this.filter[0].value.split(",")[0] : "",
to: this.filter[0] ? this.filter[0].value.split(",")[1] : ""
};
},
watch: {
filter: function (val) {
let data;
if(val[0]){
data = val[0].value.split(",");
if (data.length > 1) {
this.from = data[0];
this.to = data[1];
}
}
}
},
methods: {
/**
* Submit form handler
*/
handleSubmit() {
if (this.from && this.to) {
this.filter[0].value = this.from + "," + this.to;
}
this.$emit("updateSearchTag", this.filter);
this.$root.$emit("bv::hide::popover");
},
/**
* On ok event handler
*/
onOk() {
this.handleSubmit();
},
/**
* On click tag event handler
*/
onClickTag(tag) {
this.$root.$emit("bv::hide::popover");
},
},
};
</script>
<style scoped></style>

View File

@@ -0,0 +1,84 @@
<template>
<div id="">
<SearchPopover
:target="tag"
@savePopover="onOk"
:title="info.title"
:autoShow="info.autoShow || false"
>
<template v-slot:body>
<p>{{ info.detail }}</p>
<form ref="form" @submit.stop.prevent="handleSubmit">
<b-form-group
:state="valueState"
label-for="name-input"
:invalid-feedback="$t('ID_REQUIRED_FIELD')"
>
<b-form-input
id="name-input"
v-model="filter[0].value"
:placeholder="info.placeholder"
:state="valueState"
required
></b-form-input>
</b-form-group>
</form>
</template>
</SearchPopover>
</div>
</template>
|
<script>
import SearchPopover from "./SearchPopover.vue";
export default {
components: {
SearchPopover,
},
props: ["tag", "info", "filter"],
data() {
return {
title: "",
valueState: null,
};
},
methods: {
/**
* Check the form validations and requiered fields
*/
checkFormValidity() {
const valid = this.$refs.form.checkValidity();
this.valueState = valid;
return valid;
},
/**
* Submit form handler
*/
handleSubmit() {
let self = this;
// Exit when the form isn't valid
if (!this.checkFormValidity()) {
return;
}
this.$nextTick(() => {
this.$emit("updateSearchTag", this.filter);
self.$root.$emit("bv::hide::popover");
});
},
/**
* On ok event handler
*/
onOk() {
this.handleSubmit();
},
/**
* On ok event handler
*/
onClickTag(tag) {
this.$root.$emit("bv::hide::popover");
},
},
};
</script>
<style scoped></style>

View File

@@ -4,10 +4,11 @@
<modal-new-request ref="newRequest"></modal-new-request>
<ModalPauseCase ref="modal-pause-case"></ModalPauseCase>
<ModalReassignCase ref="modal-reassign-case"></ModalReassignCase>
<CasesFilter
<CustomFilter
:filters="filters"
:title="titleMap[data.pageParent].label"
:icon="titleMap[data.pageParent].icon"
:filterItems="filterItems"
@onRemoveFilter="onRemoveFilter"
@onUpdateFilters="onUpdateFilters"
/>
@@ -310,7 +311,7 @@ import ModalNewRequest from "../ModalNewRequest.vue";
import ModalUnpauseCase from "../modal/ModalUnpauseCase.vue";
import ModalClaimCase from "../modal/ModalClaimCase.vue";
import TaskCell from "../../components/vuetable/TaskCell.vue";
import CasesFilter from "../../components/search/CasesFilter";
import CustomFilter from "../../components/search/CustomFilter";
import api from "../../api/index";
import utils from "../../utils/utils";
import MultiviewHeader from "../../components/headers/MultiviewHeader.vue";
@@ -334,7 +335,7 @@ export default {
ModalUnpauseCase,
ModalClaimCase,
TaskCell,
CasesFilter,
CustomFilter,
MultiviewHeader,
VueCardView,
VueListView,
@@ -377,10 +378,7 @@ export default {
this.$refs["newRequest"].show();
},
},
filters:
this.settings && this.settings.filters
? this.settings.filters
: {},
filters: {},
defaultColumns: [
"case_number",
"case_title",
@@ -471,6 +469,196 @@ export default {
icon: this.data.pageIcon,
color: this.data.color
},
itemMap: {
case_number: "caseNumber",
case_title: "caseTitle",
delegation_date: "delegationDate",
send_by: "bySendBy",
process_name: "processName"
},
customItems:{
VARCHAR: {
group: "radio",
type: "VARCHAR",
id: "string",
title: `${this.$i18n.t("ID_FILTER")}:`,
optionLabel: "",
tagPrefix: "",
detail: "",
tagText: "",
placeholder: "",
items: [
{
id: "",
value: "",
},
],
autoShow: true,
makeTagText: function (params, data) {
return `${this.tagPrefix} ${data[0].value}`;
},
},
DATETIME: {
group: "radio",
type: "DATETIME",
id: "datetime",
title: `${this.$i18n.t('ID_FILTER')}:`,
optionLabel: "",
detail: "",
tagText: "",
tagPrefix: "",
items:[
{
id: "",
value: ""
}
],
makeTagText: function (params, data) {
let temp = data[0].value.split(",");
return `${this.tagPrefix} ${temp[0]} - ${temp[1]} `;
}
}
},
filterItems:[],
availableItems: {
caseNumber: {
group: "radio",
type: "CaseNumber",
id: "caseNumber",
title: `${this.$i18n.t("ID_FILTER")}: ${this.$i18n.t(
"ID_BY_CASE_NUMBER"
)}`,
optionLabel: this.$i18n.t("ID_BY_CASE_NUMBER"),
detail: this.$i18n.t("ID_PLEASE_SET_THE_CASE_NUMBER_TO_BE_SEARCHED"),
tagText: "",
tagPrefix: this.$i18n.t("ID_SEARCH_BY_CASE_NUMBER"),
items: [
{
id: "filterCases",
value: "",
},
],
autoShow: true,
makeTagText: function (params, data) {
return `${params.tagPrefix}: ${data[0].value}`;
},
},
caseTitle: {
group: "radio",
type: "CaseTitle",
id: "caseTitle",
title: `${this.$i18n.t("ID_FILTER")}: ${this.$i18n.t(
"ID_BY_CASE_TITLE"
)}`,
optionLabel: this.$i18n.t("ID_BY_CASE_TITLE"),
tagPrefix: this.$i18n.t("ID_SEARCH_BY_CASE_TITLE"),
detail: "",
tagText: "",
items: [
{
id: "caseTitle",
value: "",
},
],
autoShow: true,
makeTagText: function (params, data) {
return `${this.tagPrefix} ${data[0].value}`;
},
},
delegationDate: {
group: "radio",
type: "DateFilter",
id: "delegationDate",
title: `${this.$i18n.t('ID_FILTER')}: ${this.$i18n.t('ID_BY_DELEGATION_DATE')}`,
optionLabel: this.$i18n.t('ID_BY_DELEGATION_DATE'),
detail: this.$i18n.t('ID_PLEASE_SELECT_THE_DELEGATION_DATE_TO_BE_SEARCHED'),
tagText: "",
tagPrefix: this.$i18n.t('ID_SEARCH_BY_DELEGATION_DATE'),
items:[
{
id: "delegateFrom",
value: "",
label: this.$i18n.t('ID_FROM_DELEGATION_DATE')
},
{
id: "delegateTo",
value: "",
label: this.$i18n.t('ID_TO_DELEGATION_DATE')
}
],
makeTagText: function (params, data) {
return `${params.tagPrefix} ${data[0].value} - ${data[1].value}`;
}
},
bySendBy: {
group: "radio",
type: "CurrentUser",
id: "bySendBy",
title: `${this.$i18n.t('ID_FILTER')}: ${this.$i18n.t('ID_BY_SEND_BY')}`,
optionLabel: this.$i18n.t('ID_BY_SEND_BY'),
detail: this.$i18n.t('ID_PLEASE_SELECT_USER_NAME_TO_BE_SEARCHED'),
placeholder: this.$i18n.t('ID_USER_NAME'),
tagText: "",
tagPrefix: this.$i18n.t('ID_SEARCH_BY_SEND_BY'),
items:[
{
id: "sendBy",
value: "",
options: [],
placeholder: this.$i18n.t('ID_USER_NAME')
}
],
makeTagText: function (params, data) {
return `${params.tagPrefix} : ${data[0].label || ''}`;
}
},
taskTitle: {
group: "radio",
type: "TaskTitle",
id: "taskTitle",
title: `${this.$i18n.t("ID_FILTER")}: ${this.$i18n.t(
"ID_TASK_NAME"
)}`,
optionLabel: this.$i18n.t("ID_BY_TASK"),
detail: "",
tagText: "",
tagPrefix: this.$i18n.t("ID_SEARCH_BY_TASK_NAME"),
autoShow: true,
items: [
{
id: "task",
value: "",
options: [],
placeholder: this.$i18n.t("ID_TASK_NAME"),
},
],
makeTagText: function (params, data) {
return `${this.tagPrefix}: ${data[0].label || ""}`;
},
},
processName: {
group: "checkbox",
type: "ProcessName",
id: "processName",
title: `${this.$i18n.t('ID_FILTER')}: ${this.$i18n.t('ID_BY_PROCESS_NAME')}`,
optionLabel: this.$i18n.t('ID_BY_PROCESS_NAME'),
detail: "",
tagText: "",
tagPrefix: this.$i18n.t('ID_SEARCH_BY_PROCESS_NAME'),
autoShow: false,
items:[
{
id: "process",
value: "",
options: [],
placeholder: this.$i18n.t('ID_PROCESS_NAME')
}
],
makeTagText: function (params, data) {
return `${this.tagPrefix} ${data[0].options && data[0].options.label || ''}`;
}
}
}
};
},
created() {
@@ -605,31 +793,54 @@ export default {
limit: limit,
offset: start,
};
_.forIn(this.filters, function(item, key) {
if (filters && item.value) {
filters[item.filterVar] = item.value;
}
});
if (_.isEmpty(that.filters) && this.data.settings) {
_.forIn(this.data.settings.filters, function(item, key) {
if (filters && item.value) {
filters[item.filterVar] = item.value;
}
});
} else {
_.forIn(this.filters, function(item, key) {
if (filters && item.value) {
filters[item.filterVar] = item.value;
}
});
}
sort = that.prepareSortString(data);
if (sort) {
filters["sort"] = sort;
}
return new Promise((resolutionFunc, rejectionFunc) => {
api.cases[that.data.pageParent]
api.custom[that.data.pageParent]
({
id,
filters,
})
.then((response) => {
let tmp, columns;
columns = response.data.columns.map((item) => {
return item.field;
let tmp,
columns = [],
product,
newItems = [];
that.filterItems = [];
response.data.columns.forEach((item) => {
if (item.enableFilter) {
if (that.availableItems[that.itemMap[item.field]]) {
newItems.push(that.availableItems[that.itemMap[item.field]]);
} else {
product = this.filterItemFactory(item)
if (product) {
newItems.push(product);
}
}
}
columns.push(item.field);
});
that.filterItems = newItems;
that.settingOptions = that.formatColumnSettings(columns);
dt = that.formatDataResponse(response.data.data);
that.cardColumns = columns;
if (that.isFistTime) {
that.filters = that.settings && that.settings.filters ? that.settings.filters : {};
that.columns = that.settings && that.settings.columns ? that.settings.columns : that.getTableColumns(columns);
}
resolutionFunc({
@@ -642,6 +853,28 @@ export default {
});
});
},
/**
* Create a filter item dinamically
* @param {object} item
* @returns {object|boolean}
*/
filterItemFactory(item) {
let product;
if (item.type === "DATETIME") {
product= {...this.customItems["DATETIME"]};
} else {
product = {...this.customItems["VARCHAR"]};
}
product.title += " " + item.name;
product.id = item.field;
product.optionLabel = item.name;
product.tagPrefix = item.name;
if (product.items && product.items[0]) {
product.items[0].id = item.field;
}
product.placeholder = "";
return product;
},
/**
* Prepare sort string to be sended in the service
* @param {object} data
@@ -818,6 +1051,7 @@ export default {
* update view in component
*/
updateView(newData) {
let newCriteria = [];
this.isFistTime = true;
this.typeView = "GRID";
// force to update component id
@@ -830,10 +1064,15 @@ export default {
icon: newData.pageIcon,
color: newData.color
}
this.filters = newData.settings && newData.settings.filters ? newData.settings.filters : {};
this.data.settings = newData.settings;
this.filters = {};
}
if (this.typeView === "GRID" && this.$refs["vueTable"]) {
this.$refs["vueTable"].getData();
if (newData.settings && newData.settings.orderBy) {
this.$refs["vueTable"].setOrder(newData.settings.orderBy.column, newData.settings.orderBy.ascending);
} else {
this.$refs["vueTable"].setOrder(false);
}
}
if (this.typeView === "CARD" && this.$refs["vueCardView"]) {
this.$refs["vueCardView"].getData();

View File

@@ -83,17 +83,34 @@ export default {
dt,
typeList = that.data.pageParent == "inbox"? "todo": that.data.pageParent,
start = 0,
paged,
limit = data.limit,
filters = {};
filters = {},
id = this.data.customListId;
filters = {
paged: "0," + limit,
paged: paged,
limit: limit,
offset: start,
};
_.forIn(this.filters, function (item, key) {
filters[item.filterVar] = item.value;
});
if (_.isEmpty(that.filters) && this.data.settings) {
_.forIn(this.data.settings.filters, function(item, key) {
if (filters && item.value) {
filters[item.filterVar] = item.value;
}
});
} else {
_.forIn(this.filters, function(item, key) {
if (filters && item.value) {
filters[item.filterVar] = item.value;
}
});
}
return new Promise((resolutionFunc, rejectionFunc) => {
api.cases[typeList](filters)
api.custom[that.data.pageParent]
({
id,
filters,
})
.then((response) => {
dt = that.formatDataResponse(response.data.data);
resolutionFunc({