Merged in feature/PMCORE-3049 (pull request #7964)

PMCORE-3049 PRD

Approved-by: Henry Jonathan Quispe Quispe
Approved-by: Julio Cesar Laura Avendaño
This commit is contained in:
Paula Quispe
2021-09-06 20:40:34 +00:00
committed by Julio Cesar Laura Avendaño
214 changed files with 29643 additions and 4643 deletions

View File

@@ -9,8 +9,8 @@ $factory->define(\ProcessMaker\Model\AppDelay::class, function (Faker $faker) {
'PRO_UID' => G::generateUniqueID(),
'APP_UID' => G::generateUniqueID(),
'APP_NUMBER' => $faker->unique()->numberBetween(1000),
'APP_THREAD_INDEX' => 1,
'APP_DEL_INDEX' => $faker->unique()->numberBetween(10),
'APP_THREAD_INDEX' => $faker->unique()->numberBetween(100),
'APP_DEL_INDEX' => $faker->unique()->numberBetween(100),
'APP_TYPE' => $faker->randomElement($actions),
'APP_STATUS' => 'TO_DO',
'APP_NEXT_TASK' => 0,
@@ -28,56 +28,33 @@ $factory->define(\ProcessMaker\Model\AppDelay::class, function (Faker $faker) {
// Create a delegation with the foreign keys
$factory->state(\ProcessMaker\Model\AppDelay::class, 'paused_foreign_keys', function (Faker $faker) {
// Create values in the foreign key relations
$user = factory(\ProcessMaker\Model\User::class)->create();
$process = factory(\ProcessMaker\Model\Process::class)->create();
$task = factory(\ProcessMaker\Model\Task::class)->create([
'PRO_UID' => $process->PRO_UID,
'PRO_ID' => $process->PRO_ID
]);
$application = factory(\ProcessMaker\Model\Application::class)->create([
'PRO_UID' => $process->PRO_UID,
'APP_INIT_USER' => $user->USR_UID,
'APP_CUR_USER' => $user->USR_UID
]);
$delegation1 = factory(\ProcessMaker\Model\Delegation::class)->create([
'PRO_UID' => $process->PRO_UID,
'PRO_ID' => $process->PRO_ID,
'TAS_UID' => $task->TAS_UID,
'TAS_ID' => $task->TAS_ID,
'APP_NUMBER' => $application->APP_NUMBER,
'APP_UID' => $application->APP_UID,
'DEL_THREAD_STATUS' => 'CLOSED',
'USR_UID' => $user->USR_UID,
'USR_ID' => $user->USR_ID,
'DEL_PREVIOUS' => 0,
'DEL_INDEX' => 1
]);
$delegation = factory(\ProcessMaker\Model\Delegation::class)->create([
'PRO_UID' => $process->PRO_UID,
'PRO_ID' => $process->PRO_ID,
'TAS_UID' => $task->TAS_UID,
'TAS_ID' => $task->TAS_ID,
'APP_NUMBER' => $application->APP_NUMBER,
'APP_UID' => $application->APP_UID,
$delegation1 = factory(\ProcessMaker\Model\Delegation::class)->states('closed')->create();
$delegation2 = factory(\ProcessMaker\Model\Delegation::class)->states('foreign_keys')->create([
'PRO_UID' => $delegation1->PRO_UID,
'PRO_ID' => $delegation1->PRO_ID,
'TAS_UID' => $delegation1->TAS_UID,
'TAS_ID' => $delegation1->TAS_ID,
'APP_NUMBER' => $delegation1->APP_NUMBER,
'APP_UID' => $delegation1->APP_UID,
'DEL_THREAD_STATUS' => 'OPEN',
'USR_UID' => $user->USR_UID,
'USR_ID' => $user->USR_ID,
'USR_UID' => $delegation1->USR_UID,
'USR_ID' => $delegation1->USR_ID,
'DEL_PREVIOUS' => $delegation1->DEL_INDEX,
'DEL_INDEX' => $delegation1->DEL_INDEX++
'DEL_INDEX' => $faker->unique()->numberBetween(2000),
]);
// Return with default values
return [
'APP_DELAY_UID' => G::generateUniqueID(),
'PRO_UID' => $process->PRO_UID,
'PRO_ID' => $process->PRO_ID,
'APP_UID' => $application->APP_UID,
'APP_NUMBER' => $application->APP_NUMBER,
'APP_DEL_INDEX' => $delegation->DEL_INDEX,
'PRO_UID' => $delegation2->PRO_UID,
'PRO_ID' => $delegation2->PRO_ID,
'APP_UID' => $delegation2->APP_UID,
'APP_NUMBER' => $delegation2->APP_NUMBER,
'APP_DEL_INDEX' => $delegation2->DEL_INDEX,
'APP_TYPE' => 'PAUSE',
'APP_STATUS' => $application->APP_STATUS,
'APP_DELEGATION_USER' => $user->USR_UID,
'APP_DELEGATION_USER_ID' => $user->USR_ID,
'APP_STATUS' => 'TO_DO',
'APP_DELEGATION_USER' => $delegation2->USR_UID,
'APP_DELEGATION_USER_ID' => $delegation2->USR_ID,
'APP_ENABLE_ACTION_USER' => G::generateUniqueID(),
'APP_ENABLE_ACTION_DATE' => $faker->dateTime(),
'APP_DISABLE_ACTION_USER' => 0,

View File

@@ -7,7 +7,6 @@ $factory->define(\ProcessMaker\Model\Application::class, function(Faker $faker)
$appNumber = $faker->unique()->numberBetween(1000);
// APP_TITLE field is used in 'MYSQL: MATCH() AGAINST()' function, string size should not be less than 3.
$appTitle = $faker->lexify(str_repeat('?', rand(3, 5)) . ' ' . str_repeat('?', rand(3, 5)));
return [
'APP_UID' => G::generateUniqueID(),
'APP_TITLE' => $appTitle,
@@ -24,10 +23,10 @@ $factory->define(\ProcessMaker\Model\Application::class, function(Faker $faker)
'APP_INIT_USER' => $user->USR_UID,
'APP_CUR_USER' => $user->USR_UID,
'APP_PIN' => G::generateUniqueID(),
'APP_CREATE_DATE' => $faker->dateTime(),
'APP_INIT_DATE' => $faker->dateTime(),
'APP_UPDATE_DATE' => $faker->dateTime(),
'APP_FINISH_DATE' => $faker->dateTime(),
'APP_CREATE_DATE' => $faker->dateTimeBetween('now', '+30 minutes'),
'APP_INIT_DATE' => $faker->dateTimeBetween('now', '+30 minutes'),
'APP_UPDATE_DATE' => $faker->dateTimeBetween('now', '+30 minutes'),
'APP_FINISH_DATE' => $faker->dateTimeBetween('now', '+30 minutes'),
'APP_DATA' => serialize(['APP_NUMBER' => $appNumber])
];
});

View File

@@ -0,0 +1,26 @@
<?php
use Faker\Generator as Faker;
$factory->define(\ProcessMaker\Model\CaseList::class, function (Faker $faker) {
return [
'CAL_ID' => $faker->unique()->numberBetween(1, 2000),
'CAL_TYPE' => 'inbox',
'CAL_NAME' => $faker->title,
'CAL_DESCRIPTION' => $faker->text,
'ADD_TAB_UID' => function () {
$table = factory(\ProcessMaker\Model\AdditionalTables::class)->create();
return $table->ADD_TAB_UID;
},
'CAL_COLUMNS' => '[]',
'USR_ID' => function () {
$user = factory(\ProcessMaker\Model\User::class)->create();
return $user->USR_ID;
},
'CAL_ICON_LIST' => 'deafult.png',
'CAL_ICON_COLOR' => 'red',
'CAL_ICON_COLOR_SCREEN' => 'blue',
'CAL_CREATE_DATE' => $faker->dateTime(),
'CAL_UPDATE_DATE' => $faker->dateTime()
];
});

View File

@@ -60,11 +60,16 @@ $factory->state(\ProcessMaker\Model\Delegation::class, 'foreign_keys', function
'APP_CUR_USER' => $user->USR_UID
]);
$delegateDate = $faker->dateTime();
$initDate = $faker->dateTimeInInterval($delegateDate, '+30 minutes');
$riskDate = $faker->dateTimeInInterval($initDate, '+1 day');
$taskDueDate = $faker->dateTimeInInterval($riskDate, '+2 day');
// Return with default values
return [
'DELEGATION_ID' => $faker->unique()->numberBetween(5000),
'APP_UID' => $application->APP_UID,
'DEL_INDEX' => 1,
'DEL_INDEX' => $faker->unique()->numberBetween(2000),
'APP_NUMBER' => $application->APP_NUMBER,
'DEL_PREVIOUS' => 0,
'PRO_UID' => $process->PRO_UID,
@@ -74,10 +79,10 @@ $factory->state(\ProcessMaker\Model\Delegation::class, 'foreign_keys', function
'DEL_THREAD' => 1,
'DEL_THREAD_STATUS' => 'OPEN',
'DEL_PRIORITY' => 3,
'DEL_DELEGATE_DATE' => $faker->dateTime(),
'DEL_INIT_DATE' => $faker->dateTime(),
'DEL_TASK_DUE_DATE' => $faker->dateTime(),
'DEL_RISK_DATE' => $faker->dateTime(),
'DEL_DELEGATE_DATE' => $delegateDate,
'DEL_INIT_DATE' => $initDate,
'DEL_TASK_DUE_DATE' => $taskDueDate,
'DEL_RISK_DATE' => $riskDate,
'DEL_LAST_INDEX' => 1,
'USR_ID' => $user->USR_ID,
'PRO_ID' => $process->PRO_ID,
@@ -138,7 +143,7 @@ $factory->state(\ProcessMaker\Model\Delegation::class, 'open', function (Faker $
$delegateDate = $faker->dateTime();
$initDate = $faker->dateTimeInInterval($delegateDate, '+30 minutes');
$riskDate = $faker->dateTimeInInterval($initDate, '+1 day');
$taskDueDate = $faker->dateTimeInInterval($riskDate, '+1 day');
$taskDueDate = $faker->dateTimeInInterval($riskDate, '+2 day');
return [
'DEL_THREAD_STATUS' => 'OPEN',
@@ -156,7 +161,7 @@ $factory->state(\ProcessMaker\Model\Delegation::class, 'closed', function (Faker
$delegateDate = $faker->dateTime();
$initDate = $faker->dateTimeInInterval($delegateDate, '+30 minutes');
$riskDate = $faker->dateTimeInInterval($initDate, '+1 day');
$taskDueDate = $faker->dateTimeInInterval($riskDate, '+1 day');
$taskDueDate = $faker->dateTimeInInterval($riskDate, '+2 day');
$finishDate = $faker->dateTimeInInterval($initDate, '+10 days');
return [
@@ -171,7 +176,17 @@ $factory->state(\ProcessMaker\Model\Delegation::class, 'closed', function (Faker
// Create a last delegation
$factory->state(\ProcessMaker\Model\Delegation::class, 'last_thread', function (Faker $faker) {
return [
'DEL_LAST_INDEX' => 1,
];
});
// Create a first delegation
$factory->state(\ProcessMaker\Model\Delegation::class, 'first_thread', function (Faker $faker) {
return [
'DEL_INDEX' => 1,
'DEL_PREVIOUS' => 0,
];
});

View File

@@ -1,12 +1,15 @@
<?php
/**
* Model factory for a process category
*/
use Faker\Generator as Faker;
$factory->define(\ProcessMaker\Model\ProcessCategory::class, function (Faker $faker) {
return [
'CATEGORY_UID' => G::generateUniqueID(),
'CATEGORY_ID' => $faker->unique()->numberBetween(1000),
'CATEGORY_PARENT' => '',
'CATEGORY_NAME' => $faker->sentence(5),
'CATEGORY_ICON' => '',

View File

@@ -1,10 +1,12 @@
<?php
/**
* Model factory for a process
*/
use Faker\Generator as Faker;
$factory->define(\ProcessMaker\Model\Process::class, function(Faker $faker) {
$factory->define(\ProcessMaker\Model\Process::class, function (Faker $faker) {
return [
'PRO_UID' => G::generateUniqueID(),
@@ -24,9 +26,10 @@ $factory->define(\ProcessMaker\Model\Process::class, function(Faker $faker) {
'PRO_DYNAFORMS' => serialize([]),
'PRO_ITEE' => 1,
'PRO_ACTION_DONE' => serialize([]),
'PRO_CATEGORY' => function() {
'PRO_CATEGORY' => function () {
return factory(\ProcessMaker\Model\ProcessCategory::class)->create()->CATEGORY_UID;
},
'CATEGORY_ID' => 0
];
});
@@ -53,7 +56,7 @@ $factory->state(\ProcessMaker\Model\Process::class, 'foreign_keys', function (Fa
'PRO_DYNAFORMS' => serialize([]),
'PRO_ITEE' => 1,
'PRO_ACTION_DONE' => serialize([]),
'PRO_CATEGORY' => function() {
'PRO_CATEGORY' => function () {
return factory(\ProcessMaker\Model\ProcessCategory::class)->create()->CATEGORY_UID;
},
];

View File

@@ -7,7 +7,7 @@ use Faker\Generator as Faker;
$factory->define(\ProcessMaker\Model\TaskScheduler::class, function (Faker $faker) {
return [
'id' => G::generateUniqueID(),
'id' => $faker->unique()->numberBetween(5000),
'title' => $faker->title,
'startingTime' => $faker->dateTime(),
'endingTime' => $faker->dateTime(),

View File

@@ -1480,7 +1480,7 @@ function G_Text(form, element, name)
}
}
if (me.browser.name == 'Chrome' || me.browser.name == 'Safari' || me.browser.name == 'Firefox'){
if (me.browser.name == 'Chrome' || me.browser.name == 'Safari'){
event.returnValue = false;
}
else{

View File

@@ -999,7 +999,7 @@ else{me.applyMask(pressKey);}
if(updateOnChange){me.sendOnChange();}}
if(me.browser.name=='Firefox'){if(keyCode==0)return true;}
if(me.browser.name=='Microsoft Internet Explorer'||me.browser.name=='Netscape'){if(window.event.preventDefault){window.event.preventDefault();}else{window.event.returnValue=false;}}
if(me.browser.name=='Chrome'||me.browser.name=='Safari'||me.browser.name=='Firefox'){event.returnValue=false;}
if(me.browser.name=='Chrome'||me.browser.name=='Safari'){event.returnValue=false;}
else{return false;}}};if(this.element){this.element.onblur=function(event)
{var evt=event||window.event;var keyPressed=evt.which||evt.keyCode;if((me.mask!='')&&((me.mType=='currency')||(me.mType=='percentage')||((me.validate=="Real")&&(me.mType=='text')))&&(me.mask.indexOf('-')==-1)&&(me.element.value!='')){masks=me.mask;aMasks=masks.split(';');for(m=0;m<aMasks.length;m++){var separatorField=",";if(typeof(me.comma_separator)!='undefined'){separatorField=me.comma_separator;}else{txtRealMask=aMasks[m].split('');p=txtRealMask.length-1;for(;p>=0;p--){if(txtRealMask[p]!='#'&&txtRealMask[p]!='%'&&txtRealMask[p]!=' '){separatorField=txtRealMask[p];break;}}}
var partsMaskSep=aMasks[m].split(separatorField);if(partsMaskSep.length==2){var countDecimal=0;txtRealMask=aMasks[m].split('');p=txtRealMask.length-1;for(;p>=0;p--){if(txtRealMask[p]=='#'){countDecimal++;}

View File

@@ -409,11 +409,7 @@ class RBAC
"PER_CODE" => "PM_SETUP_CLEAR_CACHE",
"PER_NAME" => "Setup Clear Cache"
],
[
"PER_UID" => "00000000000000000000000000000025",
"PER_CODE" => "PM_SETUP_HEART_BEAT",
"PER_NAME" => "Setup Heart Beat"
],
// The 00000000000000000000000000000025 was deleted related to the heart beat
[
"PER_UID" => "00000000000000000000000000000026",
"PER_CODE" => "PM_SETUP_ENVIRONMENT",
@@ -628,6 +624,11 @@ class RBAC
'PER_UID' => '00000000000000000000000000000069',
'PER_CODE' => 'PM_TASK_SCHEDULER_ADMIN',
'PER_NAME' => 'View Task Scheduler'
],
[
'PER_UID' => '00000000000000000000000000000070',
'PER_CODE' => 'TASK_METRICS_VIEW',
'PER_NAME' => 'Task Metrics View'
]
];

1141
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -20,12 +20,18 @@
"vue-template-compiler": "^2.6.10"
},
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^1.2.35",
"@fortawesome/free-solid-svg-icons": "^5.15.3",
"@fortawesome/vue-fontawesome": "^2.0.2",
"apexcharts": "^3.27.3",
"axios": "^0.15.3",
"bootstrap": "^4.5.3",
"bootstrap-colorpicker": "^3.0.3",
"bootstrap-vue": "^2.19.0",
"bootstrap-vue-font-awesome-picker": "^0.1.3",
"chart.js": "^2.7.2",
"dateformat": "^3.0.3",
"downloadjs": "^1.4.7",
"faker": "^5.1.0",
"font-awesome": "^4.7.0",
"hammerjs": "^2.0.8",
@@ -33,12 +39,18 @@
"idempotent-babel-polyfill": "^7.4.4",
"jquery": "^3.1.1",
"lodash": "^4.17.20",
"moment": "^2.29.1",
"muuri": "^0.7.1",
"npm-font-open-sans": "^1.1.0",
"popper.js": "^1.12",
"promise-polyfill": "8.1.3",
"sortablejs": "^1.13.0",
"uiv": "^0.28.0",
"v-color": "^1.1.2",
"verte": "0.0.12",
"vfa-picker": "^5.9.1",
"vue": "^2.6.12",
"vue-apexcharts": "^1.6.1",
"vue-awesome-swiper": "^3.1.3",
"vue-chartjs": "^3.3.2",
"vue-clipboards": "^1.2.4",
@@ -46,6 +58,7 @@
"vue-faker": "^3.0.0",
"vue-fullscreen": "^2.1.3",
"vue-i18n": "^8.22.2",
"vue-icon-picker": "^1.0.0",
"vue-js-toggle-button": "^1.3.1",
"vue-multiselect": "^2.1.6",
"vue-muuri": "^0.1.2",
@@ -55,6 +68,7 @@
"vue-split-panel": "^1.0.4",
"vue-tables-2": "^2.1.46",
"vue-upload-component": "^2.8.20",
"vuedraggable": "^2.24.3",
"vuejs-auto-complete": "^0.9.0",
"vuejs-datepicker": "^1.5.4",
"vuejs-paginate": "^2.0.1",

View File

@@ -23,7 +23,6 @@ INSERT INTO `RBAC_PERMISSIONS` VALUES
('00000000000000000000000000000022','PM_SETUP_CALENDAR','2016-03-01 00:00:00','2016-03-01 00:00:00',1,'00000000000000000000000000000002'),
('00000000000000000000000000000023','PM_SETUP_PROCESS_CATEGORIES','2016-03-01 00:00:00','2016-03-01 00:00:00',1,'00000000000000000000000000000002'),
('00000000000000000000000000000024','PM_SETUP_CLEAR_CACHE','2016-03-01 00:00:00','2016-03-01 00:00:00',1,'00000000000000000000000000000002'),
('00000000000000000000000000000025','PM_SETUP_HEART_BEAT','2016-03-01 00:00:00','2016-03-01 00:00:00',1,'00000000000000000000000000000002'),
('00000000000000000000000000000026','PM_SETUP_ENVIRONMENT','2016-03-01 00:00:00','2016-03-01 00:00:00',1,'00000000000000000000000000000002'),
('00000000000000000000000000000027','PM_SETUP_PM_TABLES','2016-03-01 00:00:00','2016-03-01 00:00:00',1,'00000000000000000000000000000002'),
('00000000000000000000000000000028','PM_SETUP_LOGIN','2016-03-01 00:00:00','2016-03-01 00:00:00',1,'00000000000000000000000000000002'),
@@ -66,7 +65,8 @@ INSERT INTO `RBAC_PERMISSIONS` VALUES
('00000000000000000000000000000065','PM_SETUP_CUSTOM_CASES_LIST','2017-03-27 00:00:00','2017-03-27 00:00:00',1,'00000000000000000000000000000002'),
('00000000000000000000000000000066','PM_GUEST_CASE','2017-03-27 00:00:00','2017-03-27 00:00:00',1,'00000000000000000000000000000002'),
('00000000000000000000000000000067','PM_SETUP_LOG_FILES','2018-02-06 00:00:00','2018-02-06 00:00:00',1,'00000000000000000000000000000002'),
('00000000000000000000000000000068','PM_FOLDERS_OWNER','2020-01-29 00:00:00','2020-01-29 00:00:00',1,'00000000000000000000000000000002');
('00000000000000000000000000000068','PM_FOLDERS_OWNER','2020-01-29 00:00:00','2020-01-29 00:00:00',1,'00000000000000000000000000000002'),
('00000000000000000000000000000070','TASK_METRICS_VIEW','2021-07-14 00:00:00','2021-07-14 00:00:00',1,'00000000000000000000000000000002');
INSERT INTO `RBAC_PERMISSIONS` VALUES
('00000000000000000000000000000069','PM_TASK_SCHEDULER_ADMIN','2020-01-29 00:00:00','2020-01-29 00:00:00',1,'00000000000000000000000000000002');
@@ -104,7 +104,6 @@ INSERT INTO `RBAC_ROLES_PERMISSIONS` VALUES
('00000000000000000000000000000002','00000000000000000000000000000022'),
('00000000000000000000000000000002','00000000000000000000000000000023'),
('00000000000000000000000000000002','00000000000000000000000000000024'),
('00000000000000000000000000000002','00000000000000000000000000000025'),
('00000000000000000000000000000002','00000000000000000000000000000026'),
('00000000000000000000000000000002','00000000000000000000000000000027'),
('00000000000000000000000000000002','00000000000000000000000000000028'),
@@ -148,6 +147,7 @@ INSERT INTO `RBAC_ROLES_PERMISSIONS` VALUES
('00000000000000000000000000000002','00000000000000000000000000000067'),
('00000000000000000000000000000002','00000000000000000000000000000068'),
('00000000000000000000000000000002','00000000000000000000000000000069'),
('00000000000000000000000000000002','00000000000000000000000000000070'),
('00000000000000000000000000000003','00000000000000000000000000000001'),
('00000000000000000000000000000003','00000000000000000000000000000005'),
('00000000000000000000000000000003','00000000000000000000000000000040'),
@@ -185,7 +185,6 @@ INSERT INTO `RBAC_ROLES_PERMISSIONS` VALUES
('00000000000000000000000000000004','00000000000000000000000000000022'),
('00000000000000000000000000000004','00000000000000000000000000000023'),
('00000000000000000000000000000004','00000000000000000000000000000024'),
('00000000000000000000000000000004','00000000000000000000000000000025'),
('00000000000000000000000000000004','00000000000000000000000000000026'),
('00000000000000000000000000000004','00000000000000000000000000000027'),
('00000000000000000000000000000004','00000000000000000000000000000028'),

View File

@@ -0,0 +1,67 @@
<template>
<div>
<b-modal
ref="modal-delete-list"
hide-footer
size="md"
>
<template v-slot:modal-title>
{{ $t('ID_DELETE_CUSTOM_CASE_LIST') }}
</template>
<b-container fluid>
<p>
{{ $t("ID_ARE_YOU_SURE_DELETE_CUSTOM_CASE_LIST", {'CUSTOM_NAME': data.name}) }}
</p>
</b-container>
<div class="modal-footer">
<div class="float-right">
<b-button
variant="danger"
data-dismiss="modal"
@click="hide"
>
{{ $t("ID_NO") }}
</b-button>
<b-button
variant="success"
@click="deleteCustomCaseList"
>
{{ $t("ID_YES") }}
</b-button>
</div>
</div>
</b-modal>
</div>
</template>
<script>
import api from "./../settings/customCaseList/Api/CaseList";
export default {
name: "ModalDeleteCaseList",
data() {
return {
data: {
name: null
}
}
},
methods: {
show() {
this.$refs["modal-delete-list"].show();
},
hide() {
this.$refs["modal-delete-list"].hide();
},
deleteCustomCaseList() {
let that = this;
api.deleteCaseList(this.data).then((response) => {
if (response.statusText === "OK") {
that.$refs["modal-delete-list"].hide();
that.$parent.$refs["table"].getData();
that.$parent.$refs['ellipsis-' + that.data.id].hideActionButtons();
}
});
}
}
}
</script>

View File

@@ -0,0 +1,199 @@
<template>
<div>
<b-modal
ref="modal-import"
hide-footer
size="md"
>
<template v-slot:modal-title>
{{ $t('ID_IMPORT_CUSTOM_CASE_LIST') }}
</template>
<b-container fluid>
<div v-if="!caseListDuplicate">
{{ $t('ID_PLEASE_ADD_THE_CUSTOM_LIST_FILE_TO_BE_UPLOADED') }}
</div>
<div v-if="caseListDuplicate">
{{ message }}
</div>
<div>
<b-form-file
v-model="fileCaseList"
:state="validFile"
ref="file-input"
:disabled="caseListDuplicate"
></b-form-file>
</div>
<p>
</p>
</b-container>
<div class="modal-footer">
<div class="float-right">
<b-button
variant="danger"
data-dismiss="modal"
@click="hide"
>
{{ $t("ID_CANCEL") }}
</b-button>
<b-button
variant="success"
v-if="!caseListDuplicate"
@click="importCustomCaseList"
>
{{ $t("ID_SAVE") }}
</b-button>
<b-button
variant="info"
v-if="caseListDuplicate"
@click="continueImport()"
>
{{ $t("ID_CONTINUE") }}
</b-button>
</div>
</div>
</b-modal>
<!-- pmTable does not exist in the workspace -->
<b-modal
size="md"
ok-only
:ok-title="$t('ID_CLOSE')"
ok-variant="danger"
v-model="pmTableNoExist"
>
<template v-slot:modal-title>
{{ $t('ID_IMPORT_CUSTOM_CASE_LIST') }}
</template>
<b-container fluid>
<div>
{{ message }}
</div>
</b-container>
</b-modal>
<!-- pmTable incomplete columns for custom case list -->
<b-modal
hide-footer
size="md"
v-model="pmTableNoFields"
>
<template v-slot:modal-title>
{{ $t('ID_IMPORT_CUSTOM_CASE_LIST') }}
</template>
<b-container fluid>
<div>
{{ message }}
</div>
</b-container>
<div class="modal-footer">
<div class="float-right">
<b-button
variant="danger"
data-dismiss="modal"
@click="close"
>
{{ $t("ID_CLOSE") }}
</b-button>
<b-button
variant="info"
@click="continueImport"
>
{{ $t("ID_CONTINUE") }}
</b-button>
</div>
</div>
</b-modal>
</div>
</template>
<script>
import api from "./../settings/customCaseList/Api/CaseList";
export default {
name: "ModalImport",
data() {
return {
data: [],
validFile: null,
fileCaseList: null,
caseListDuplicate: false,
pmTableNoFields: false,
pmTableNoExist: false,
message: ''
}
},
methods: {
show() {
this.caseListDuplicate = false;
this.$refs["modal-import"].show();
},
/**
* Close table
*/
close() {
this.pmTableNoFields = false;
},
/**
* Hide modal import
*/
hide() {
this.caseListDuplicate = false;
this.$refs["modal-import"].hide();
},
/**
* Get the custom list case API
*/
importCustomCaseList() {
let that = this;
this.data.file = this.fileCaseList;
api.importCaseList(this.data)
.then((response) => {
switch (response.data.status) {
case 'tableNotExist': // pmTable does not exist
that.pmTableNoExist = true;
that.message = response.data.message
that.$refs["modal-import"].hide();
break;
case 'duplicateName': // Custom Case List duplicate
that.caseListDuplicate = true;
that.message = response.data.message
that.validFile = null;
break;
case 'invalidFields': // pmTable differentes columns
that.pmTableNoFields = true;
that.message = response.data.message
that.$refs["modal-import"].hide();
break;
default: // import without error
that.$refs["modal-import"].hide();
that.$parent.$refs["table"].getData();
break;
}
})
.catch((e) => {
console.error(e);
});
},
/**
* Continue import custom case list
*/
continueImport() {
let that = this;
this.data.file = this.fileCaseList;
if (this.pmTableNoFields) {
this.data.continue = 'invalidFields';
}
if (this.caseListDuplicate) {
this.data.continue = 'duplicateName';
}
api.importCaseList(this.data)
.then((response) => {
if (response.status === 200) {
that.$refs["modal-import"].hide();
that.$parent.$refs["table"].getData();
}
})
.catch((e) => {
console.error(e);
});
}
}
}
</script>

View File

@@ -0,0 +1,279 @@
<template>
<b-modal
ref="modal-preview"
scrollable
size="xl"
>
<template v-slot:modal-title></template>
<b-container fluid>
<v-server-table
:data="tableData"
:columns="columns"
:options="options"
ref="table-preview"
name="preview"
>
<div slot="detail">
<i class="fas fa-info-circle"></i>
</div>
<div slot="case_number" slot-scope="props">
{{ props.row.CASE_NUMBER }}
</div>
<div slot="case_title" slot-scope="props">
{{ props.row.CASE_TITLE }}
</div>
<div slot="process_name" slot-scope="props">
{{ props.row.PROCESS_NAME }}
</div>
<div slot="task" slot-scope="props">
<TaskCell :data="props.row.TASK" />
</div>
<div slot="send_by" slot-scope="props">
<CurrentUserCell :data="props.row.USER_DATA" />
</div>
<div slot="current_user" slot-scope="props">
{{ props.row.USERNAME_DISPLAY_FORMAT }}
</div>
<div slot="due_date" slot-scope="props">
{{ props.row.DUE_DATE }}
</div>
<div slot="delegation_date" slot-scope="props">
{{ props.row.DELEGATION_DATE }}
</div>
<div slot="priority" slot-scope="props">
{{ props.row.PRIORITY }}
</div>
<div slot="actions">
<i class="fas fa-ellipsis-v"></i>
</div>
</v-server-table>
</b-container>
<template #modal-footer>
<b-button
variant="danger"
data-dismiss="modal"
@click="cancel"
>
{{ $t("ID_CANCEL") }}
</b-button>
</template>
</b-modal>
</template>
<script>
import api from "../../api/index";
import utils from "../../utils/utils";
import TaskCell from "../../components/vuetable/TaskCell.vue";
import CurrentUserCell from "../../components/vuetable/CurrentUserCell.vue"
export default {
name: "ModalPreview",
props: [],
components: {
TaskCell,
CurrentUserCell,
},
data() {
return {
type: null,
columns: null,
tableData: [],
options: {
filterable: false,
pagination: {
show: false
},
headings: {
detail: this.$i18n.t("ID_DETAIL_CASE"),
case_number: this.$i18n.t("ID_MYCASE_NUMBER"),
case_title: this.$i18n.t("ID_CASE_TITLE"),
process_name: this.$i18n.t("ID_PROCESS_NAME"),
task: this.$i18n.t("ID_TASK"),
send_by: this.$i18n.t("ID_SEND_BY"),
due_date: this.$i18n.t("ID_DUE_DATE"),
delegation_date: this.$i18n.t("ID_DELEGATION_DATE"),
priority: this.$i18n.t("ID_PRIORITY"),
actions: "",
},
requestFunction(data) {
return this.$parent.$parent.$parent.$parent.getCasesForPreview(data)
},
},
customCaseId: '',
statusTitle: {
ON_TIME: this.$i18n.t("ID_IN_PROGRESS"),
OVERDUE: this.$i18n.t("ID_TASK_OVERDUE"),
DRAFT: this.$i18n.t("ID_IN_DRAFT"),
PAUSED: this.$i18n.t("ID_PAUSED"),
UNASSIGNED: this.$i18n.t("ID_UNASSIGNED"),
},
}
},
mounted() {
},
methods: {
show() {
this.$refs["modal-preview"].show();
},
cancel() {
this.$refs["modal-preview"].hide();
},
/**
* Get cases data
*/
getCasesForPreview(data) {
let that = this,
dt,
paged,
limit = data.limit,
start = data.page === 1 ? 0 : limit * (data.page - 1),
filters = {};
paged = start + "," + limit;
filters = {
paged: paged,
}
if (this.customCaseId !== '') {
filters['id'] = this.customCaseId;
}
return new Promise((resolutionFunc, rejectionFunc) => {
switch (that.type) {
case 'inbox':
api.cases
.inbox(filters)
.then((response) => {
dt = that.formatDataResponse(response.data.data);
resolutionFunc({
data: dt,
count: response.data.total,
});
})
.catch((e) => {
rejectionFunc(e);
});
break;
case 'draft':
api.cases
.draft(filters)
.then((response) => {
dt = that.formatDataResponse(response.data.data);
resolutionFunc({
data: dt,
count: response.data.total,
});
})
.catch((e) => {
rejectionFunc(e);
});
break;
case 'paused':
api.cases
.paused(filters)
.then((response) => {
dt = that.formatDataResponse(response.data.data);
resolutionFunc({
data: dt,
count: response.data.total,
});
})
.catch((e) => {
rejectionFunc(e);
});
break;
case 'unassigned':
api.cases
.unassigned(filters)
.then((response) => {
dt = that.formatDataResponse(response.data.data);
resolutionFunc({
data: dt,
count: response.data.total,
});
})
.catch((e) => {
rejectionFunc(e);
});
break;
}
});
},
/**
* Format Response API custom case list to grid todo and columns
* @param {object} response
* @returns {object}
*/
formatDataResponse(response) {
let data = [];
_.forEach(response, (v) => {
data.push({
...v,
...{
CASE_NUMBER: v.APP_NUMBER,
CASE_TITLE: v.DEL_TITLE,
PROCESS_NAME: v.PRO_TITLE,
TASK: [
{
TITLE: v.TAS_TITLE,
CODE_COLOR: v.TAS_COLOR,
COLOR: v.TAS_COLOR_LABEL,
DELAYED_TITLE:
v.TAS_STATUS === "OVERDUE"
? this.$i18n.t("ID_DELAYED") + ":"
: this.statusTitle[v.TAS_STATUS],
DELAYED_MSG:
v.TAS_STATUS === "OVERDUE" ? v.DELAY : "",
},
],
USER_DATA: this.formatUser(v.SEND_BY_INFO),
USERNAME_DISPLAY_FORMAT: utils.userNameDisplayFormat({
userName: v.USR_LASTNAME,
firstName: v.USR_LASTNAME,
lastName: v.USR_LASTNAME,
format: window.config.FORMATS.format || null,
}),
DUE_DATE: v.DEL_TASK_DUE_DATE_LABEL,
DELEGATION_DATE: v.DEL_DELEGATE_DATE_LABEL,
PRIORITY: v.DEL_PRIORITY_LABEL,
DEL_INDEX: v.DEL_INDEX,
APP_UID: v.APP_UID,
PRO_UID: v.PRO_UID,
TAS_UID: v.TAS_UID,
}
});
});
return data;
},
/**
* Set the format to show user's information
* @return {array} dataFormat
*/
formatUser(data) {
var dataFormat = [],
userDataFormat;
userDataFormat = utils.userNameDisplayFormat({
userName: data.user_tooltip.usr_firstname,
firstName: data.user_tooltip.usr_lastname,
lastName: data.user_tooltip.usr_username,
format: window.config.FORMATS.format || null
});
dataFormat.push({
USERNAME_DISPLAY_FORMAT: userDataFormat,
EMAIL: data.user_tooltip.usr_email,
POSITION: data.user_tooltip.usr_position,
AVATAR: userDataFormat !== "" ? window.config.SYS_SERVER_AJAX +
window.config.SYS_URI +
`users/users_ViewPhotoGrid?pUID=${data.user_tooltip.usr_id}` : "",
UNASSIGNED: userDataFormat !== "" ? true : false
});
return dataFormat;
}
}
}
</script>
<style>
.VueTables__limit-field {
display: none;
}
.table-responsive {
margin-top: -1rem;
}
</style>

View File

@@ -0,0 +1,129 @@
import axios from "axios";
import Api from "../../../../api/Api";
import Services from "./Services";
import Defaults from "./Mocks/defaults.json";
class caseListApi extends Api {
constructor(services) {
// Here, it calls the parent class' constructor with lengths
// provided for the Polygon's width and height
super(services, services);
}
/**
* Get the case list
* @param {object} data
* @param {string} module
*/
getCaseList(data, module) {
let service = "CASE_LIST_TODO";
switch (module) {
case 'inbox' :
service = "CASE_LIST_TODO";
break;
case 'draft' :
service = "CASE_LIST_DRAFT";
break;
case 'unassigned' :
service = "CASE_LIST_UNASSIGNED";
break;
case 'paused' :
service = "CASE_LIST_PAUSED";
break;
}
return this.get({
service: service,
params: data,
keys: {}
});
}
/**
* Service delete case list
* @param {*} data
* @returns
*/
deleteCaseList(data) {
return axios.delete(
window.config.SYS_SERVER_API +
'/api/1.0/' +
window.config.SYS_WORKSPACE +
'/caseList/' + data.id, {
headers: {
'Authorization': 'Bearer ' + window.config.SYS_CREDENTIALS.accessToken,
"Accept-Language": window.config.SYS_LANG
}
}
);
}
/**
* Service return report tables
* @param {*} data
* @returns
*/
reportTables(data) {
return this.get({
service: 'REPORT_TABLES',
params: data,
keys: {}
});
}
/**
* Service default columns
* @param {*} type
* @returns
*/
getDefault(type){
return this.get({
service: 'DEFAULT_COLUMNS',
keys: {
type: type
}
});
}
/**
* Service create case list
* @param {*} data
* @returns
*/
createCaseList(data) {
return this.post({
service: "CASE_LIST",
data: data
});
}
/**
* Service update case list
* @param {*} data
* @returns
*/
updateCaseList(data) {
return this.put({
service: "PUT_CASE_LIST",
keys: {
id: data.id
},
data: data
});
}
/**
* Service import case list
* @param {*} data
* @returns
*/
importCaseList(data) {
let formData = new FormData();
formData.append('file_content', data.file);
if (data.continue) {
formData.append(data.continue, 'continue');
}
return this.post({
service: "IMPOR_CASE_LIST",
data: formData,
headers:{
'Content-Type': 'multipart/form-data'
},
})
}
}
let api = new caseListApi(Services);
export default api;

View File

@@ -0,0 +1,300 @@
{
"inbox": [
{
"field": "case_number",
"name": "Case #",
"type": "integer",
"source": "APPLICATION",
"typeSearch": "integer range",
"enableFilter": false,
"set": true
},
{
"field": "case_title",
"name": "Case Title",
"type": "string",
"source": "APPLICATION",
"typeSearch": "search text",
"enableFilter": false,
"set": true
},
{
"field": "process_name",
"name": "Process Name",
"type": "string",
"source": "APPLICATION",
"typeSearch": "search text",
"enableFilter": false,
"set": true
},
{
"field": "task",
"name": "Task",
"type": "string",
"source": "APPLICATION",
"typeSearch": "search text",
"enableFilter": false,
"set": true
},
{
"field": "send_by",
"name": "**ID_SEND_BY**",
"type": "string",
"source": "APPLICATION",
"typeSearch": "search text",
"enableFilter": false,
"set": true
},
{
"field": "due_date",
"name": "Due Date",
"type": "date",
"source": "APPLICATION",
"typeSearch": "date range",
"enableFilter": false,
"set": true
},
{
"field": "delegation_date",
"name": "Delegation Date",
"type": "date",
"source": "APPLICATION",
"typeSearch": "date range",
"enableFilter": false,
"set": true
},
{
"field": "priority",
"name": "Priority",
"type": "string",
"source": "APPLICATION",
"typeSearch": "option",
"enableFilter": false,
"set": true
}
],
"draft": [
{
"field": "case_number",
"name": "Case #",
"type": "integer",
"source": "APPLICATION",
"typeSearch": "integer range",
"enableFilter": false,
"set": true
},
{
"field": "case_title",
"name": "Case Title",
"type": "string",
"source": "APPLICATION",
"typeSearch": "search text",
"enableFilter": false,
"set": true
},
{
"field": "process_name",
"name": "Process Name",
"type": "string",
"source": "APPLICATION",
"typeSearch": "search text",
"enableFilter": false,
"set": true
},
{
"field": "task",
"name": "Task",
"type": "string",
"source": "APPLICATION",
"typeSearch": "search text",
"enableFilter": false,
"set": true
}
],
"paused": [
{
"field": "case_number",
"name": "Case #",
"type": "integer",
"source": "APPLICATION",
"typeSearch": "integer range",
"enableFilter": false,
"set": true
},
{
"field": "case_title",
"name": "Case Title",
"type": "string",
"source": "APPLICATION",
"typeSearch": "search text",
"enableFilter": false,
"set": true
},
{
"field": "process_name",
"name": "Process Name",
"type": "string",
"source": "APPLICATION",
"typeSearch": "search text",
"enableFilter": false,
"set": true
},
{
"field": "task",
"name": "Task",
"type": "string",
"source": "APPLICATION",
"typeSearch": "search text",
"enableFilter": false,
"set": true
},
{
"field": "send_by",
"name": "**ID_SEND_BY**",
"type": "string",
"source": "APPLICATION",
"typeSearch": "search text",
"enableFilter": false,
"set": true
},
{
"field": "due_date",
"name": "Due Date",
"type": "date",
"source": "APPLICATION",
"typeSearch": "date range",
"enableFilter": false,
"set": true
},
{
"field": "delegation_date",
"name": "Delegation Date",
"type": "date",
"source": "APPLICATION",
"typeSearch": "date range",
"enableFilter": false,
"set": true
},
{
"field": "priority",
"name": "Priority",
"type": "string",
"source": "APPLICATION",
"typeSearch": "option",
"enableFilter": false,
"set": true
}
],
"inbox": [
{
"field": "case_number",
"name": "Case #",
"type": "integer",
"source": "APPLICATION",
"typeSearch": "integer range",
"enableFilter": false,
"set": true
},
{
"field": "case_title",
"name": "Case Title",
"type": "string",
"source": "APPLICATION",
"typeSearch": "search text",
"enableFilter": false,
"set": true
},
{
"field": "process_name",
"name": "Process Name",
"type": "string",
"source": "APPLICATION",
"typeSearch": "search text",
"enableFilter": false,
"set": true
},
{
"field": "task",
"name": "Task",
"type": "string",
"source": "APPLICATION",
"typeSearch": "search text",
"enableFilter": false,
"set": true
},
{
"field": "send_by",
"name": "**ID_SEND_BY**",
"type": "string",
"source": "APPLICATION",
"typeSearch": "search text",
"enableFilter": false,
"set": true
},
{
"field": "due_date",
"name": "Due Date",
"type": "date",
"source": "APPLICATION",
"typeSearch": "date range",
"enableFilter": false,
"set": true
},
{
"field": "delegation_date",
"name": "Delegation Date",
"type": "date",
"source": "APPLICATION",
"typeSearch": "date range",
"enableFilter": false,
"set": true
},
{
"field": "priority",
"name": "Priority",
"type": "string",
"source": "APPLICATION",
"typeSearch": "option",
"enableFilter": false,
"set": true
}
],
"unassigned": [
{
"field": "case_number",
"name": "Case #",
"type": "integer",
"source": "APPLICATION",
"typeSearch": "integer range",
"enableFilter": false,
"set": true
},
{
"field": "case_title",
"name": "Case Title",
"type": "string",
"source": "APPLICATION",
"typeSearch": "search text",
"enableFilter": false,
"set": true
},
{
"field": "process_name",
"name": "Process Name",
"type": "string",
"source": "APPLICATION",
"typeSearch": "search text",
"enableFilter": false,
"set": true
},
{
"field": "task",
"name": "Task",
"type": "string",
"source": "APPLICATION",
"typeSearch": "search text",
"enableFilter": false,
"set": true
}
]
}

View File

@@ -0,0 +1,11 @@
export default {
CASE_LIST_TODO: "/caseList/inbox",
CASE_LIST_DRAFT: "/caseList/draft",
CASE_LIST_UNASSIGNED: "/caseList/unassigned",
CASE_LIST_PAUSED: "/caseList/paused",
REPORT_TABLES: "/caseList/report-tables",
CASE_LIST: "/caseList",
DEFAULT_COLUMNS: "/caseList/{type}/default-columns",
PUT_CASE_LIST: "/caseList/{id}",
IMPOR_CASE_LIST: "/caseList/import"
};

View File

@@ -0,0 +1,772 @@
<template>
<div id="home">
<ModalPreview ref="modal-preview"></ModalPreview>
<div class="demo">
<div class="container">
<h5>{{ $t("ID_NEW_CASES_LISTS") }} ({{ module.title }})</h5>
<b-form @submit="onSubmit">
<b-row>
<b-col cols="6">
<b-row>
<b-col cols="6">
<b-form-group
id="nameLabel"
:label="$t('ID_NAME')"
label-for="name"
>
<b-form-input
id="name"
v-model="params.name"
:state="isValidName"
:placeholder="
$t('ID_SET_A_CASE_LIST_NAME')
"
></b-form-input>
<b-form-invalid-feedback
:state="isValidName"
>
{{ $t("ID_REQUIRED_FIELD") }}
</b-form-invalid-feedback>
</b-form-group>
</b-col>
<b-col cols="6">
<div :class="{ invalid: isValidTable === false }">
<label>{{ $t("ID_PM_TABLE") }}</label>
<multiselect
v-model="pmTable"
:options="pmTablesOptions"
:placeholder="
$t('ID_CHOOSE_OPTION')
"
label="label"
track-by="value"
:show-no-results="false"
@search-change="asyncFind"
@select="onSelect"
:loading="isLoading"
id="ajax"
:limit="10"
:clear-on-select="true"
>
</multiselect>
<label
:class="{
'd-block invalid-feedback': isValidTable === false
}"
v-show="isValidTable === false"
>{{
$t("ID_REQUIRED_FIELD")
}}</label
>
</div>
</b-col>
</b-row>
<b-form-group
id="descriptionLabel"
:label="$t('ID_DESCRIPTION')"
label-for="description"
>
<b-form-textarea
id="description"
v-model="params.description"
:placeholder="$t('ID_SOME_TEXT')"
rows="1"
max-rows="1"
></b-form-textarea>
</b-form-group>
<b-row>
<b-col cols="11">
<v-client-table
:columns="columns"
v-model="data"
:options="options"
ref="pmTableColumns"
>
<!-- checkbox for each header (prefix column name with h__-->
<template slot="h__selected">
<input
type="checkbox"
@click="selectAllAtOnce()"
/>
</template>
<input
slot="selected"
slot-scope="props"
type="checkbox"
v-model="checkedRows"
:checked="props.row.selected"
:value="props.row.field"
/>
<div slot="action" slot-scope="props">
<b-button
variant="light"
@click="onAddRow(props.row)"
>
<i
ref="iconClose"
class="fas fa-plus"
></i>
</b-button>
</div>
</v-client-table>
</b-col>
<b-col cols="1">
<!-- Control panel -->
<div class="control-panel">
<div class="vertical-center">
<button
type="button"
class="btn btn-light"
@click="assignAll()"
:disabled="isButtonDisabled"
>
<i
class="fa fa-angle-double-right"
></i>
</button>
<button
type="button"
class="btn btn-light"
@click="assignSelected()"
:disabled="isButtonDisabled"
>
<i
class="fa fa-angle-right"
></i>
</button>
<button
type="button"
class="btn btn-light"
@click="unassignSelected()"
:disabled="isButtonDisabled"
>
<i class="fa fa-angle-left"></i>
</button>
<button
type="button"
class="btn btn-light"
@click="unassignAll()"
:disabled="isButtonDisabled"
>
<i
class="fa fa-angle-double-left"
></i>
</button>
</div>
</div>
<!-- End Control panel -->
</b-col>
</b-row>
<b-form-group
id="iconLabel"
:label="$t('ID_ICON')"
label-for="icon"
>
<icon-picker
@selected="onSelectIcon"
:default="params.iconList"
/>
</b-form-group>
<div>
<b-form-group
id="menuColor"
:label="$t('ID_MENU_COLOR')"
label-for="icon"
>
<verte
:value="params.iconColor"
id="icon"
@input="onChangeColor"
picker="square"
menuPosition="left"
model="hex"
>
<svg viewBox="0 0 50 50">
<path
d="M 10 10 H 90 V 90 H 10 L 10 10"
/>
</svg>
</verte>
</b-form-group>
</div>
<div>
<b-form-group
id="screenColor"
:label="$t('ID_SCREEN_COLOR_ICON')"
label-for="screen"
>
<verte
:value="params.iconColorScreen"
@input="onChangeColorScreen"
picker="square"
menuPosition="left"
model="hex"
>
<svg viewBox="0 0 50 50">
<path
d="M 10 10 H 90 V 90 H 10 L 10 10"
/>
</svg>
</verte>
</b-form-group>
</div>
</b-col>
<b-col cols="6">
<b-form-group
id="caseListFieldset"
:label="$t('ID_CASE_LIST')"
>
<v-client-table
:columns="columnsCaseList"
v-model="dataCaseList"
:options="caseListOptions"
>
<!-- checkbox for each header (prefix column name with h__-->
<template slot="h__selected">
<input
type="checkbox"
@click="selectAllAtOnceCaseList()"
/>
</template>
<input
slot="selected"
slot-scope="props"
type="checkbox"
v-model="checkedRowsCaseList"
:checked="props.row.selected"
:value="props.row.field"
/>
<div slot="enableFilter" slot-scope="props">
<b-row>
<b-col cols="6">
<i
ref="iconClose"
class="fas fa-info-circle"
:id="`popover-1-${props.row.field}`"
></i>
<b-popover
:target="`popover-1-${props.row.field}`"
placement="top"
triggers="hover focus"
:content="searchInfoContent(props.row)"
></b-popover>
</b-col>
<b-col cols="6">
<b-form-checkbox
v-model="enabledFilterRows"
@change="onTongleFilter(props.row.field)"
name="check-button"
:checked="props.row.enableFilter"
:value="props.row.field"
switch
>
</b-form-checkbox>
</b-col>
</b-row>
</div>
<div slot="action" slot-scope="props">
<b-button
variant="light"
@click="onRemoveRow(props.row)"
>
<i
ref="iconClose"
class="fas fa-minus"
></i>
</b-button>
</div>
</v-client-table>
</b-form-group>
</b-col>
</b-row>
<div>
<b-button tvariant="danger" @click="onCancel">{{
$t("ID_CANCEL")
}}</b-button>
<b-button variant="outline-primary" @click="showPreview">{{
$t("ID_PREVIEW")
}}</b-button>
<b-button type="submit" variant="primary">{{
$t("ID_SAVE")
}}</b-button>
</div>
</b-form>
</div>
</div>
</div>
</template>
<script>
import utils from "../../../utils/utils";
import Multiselect from "vue-multiselect";
import Api from "./Api/CaseList";
import IconPicker from "../../../components/iconPicker/IconPicker.vue";
import ModalPreview from "../../Modals/ModalPreview.vue";
export default {
name: "CaseListSketh",
components: {
Multiselect,
IconPicker,
IconPicker,
ModalPreview,
},
props: ["params", "module"],
data() {
return {
icon: "fas fa-user-cog",
isLoading: false,
isButtonDisabled: false,
isSelected: false,
isSelectedCaseList: false,
pmTablesOptions: [],
checkedRows: [],
enabledFilterRows: [],
closedRows: [],
checkedRowsCaseList: [],
columns: ["selected", "name", "field", "type", "source", "action"],
data: [],
options: {
headings: {
name: this.$i18n.t("ID_NAME"),
field: this.$i18n.t("ID_FIELD"),
type: this.$i18n.t("ID_TYPE"),
source: this.$i18n.t("ID_SOURCE"),
action: "",
},
sortable: [],
filterable: true,
perPage: 1000,
perPageValues: [],
texts: {
count: "",
},
},
dataCaseList: [],
columnsCaseList: [
"selected",
"name",
"field",
"type",
"typeSearch",
"enableFilter",
"action",
],
caseListOptions: {
headings: {
name: this.$i18n.t("ID_NAME"),
field: this.$i18n.t("ID_FIELD"),
type: this.$i18n.t("ID_TYPE"),
typeSearch: this.$i18n.t("ID_TYPE_OF_SEARCHING"),
enableFilter: this.$i18n.t("ID_ENABLE_SEARCH_FILTER"),
action: "",
},
filterable: false,
perPage: 1000,
perPageValues: [],
sortable: [],
texts: {
count: "",
},
},
defaultCaseList: [],
isValidName: null,
isValidTable: null,
pmTable: null,
isPreview: false
};
},
computed: {
validation() {
return this.params.name !== "";
},
},
mounted() {
this.getDefaultColumns(this.module.key);
if(this.params.id) {
this.editMode();
}
},
methods: {
/**
* Prepare search popover info
* @param {object} row
* @returns {string}
*/
searchInfoContent(row) {
let info = this.$i18n.t("ID_THE_SEARCH_WILL_BE_FROM");
switch (row.type) {
case 'integer':
info += " " + this.$i18n.t("ID_A_RANGE_OF_VALUES");
break;
case 'string':
info += " " + this.$i18n.t("ID_A_TEXT_SEARCH");
break;
case 'date':
info += " " + this.$i18n.t("ID_DATE_TO_DATE");
break;
default:
info = this.$i18n.t("ID_NO_SEARCHING_METHOD");
}
return info;
},
/**
* Edit mode handler
* prepare the datato be rendered
*/
editMode(){
let that = this;
this.pmTable = {
label: this.params.tableName,
value: this.params.tableUid
}
this.data =this.params.columns.filter(elem => elem.set === false);
this.dataCaseList =this.params.columns.filter(elem => elem.set === true);
this.dataCaseList.forEach(function (value) {
if (value.enableFilter) {
that.enabledFilterRows.push(value.field);
}
});
},
/**
* Select all checkbox handler into available pm tables column list
*/
selectAllAtOnce() {
let length = this.data.length;
this.isSelected = !this.isSelected;
this.checkedRows = [];
for (let i = 0; i < length; i++) {
this.data[i].selected = this.isSelected;
if (this.isSelected) {
this.checkedRows.push(this.data[i].field);
}
}
},
/**
* Select all checkbox handler into case list table
*/
selectAllAtOnceCaseList() {
let length = this.dataCaseList.length;
this.isSelectedCaseList = !this.isSelectedCaseList;
this.checkedRowsCaseList = [];
for (let i = 0; i < length; i++) {
this.dataCaseList[i].selected = this.isSelectedCaseList;
if (this.isSelectedCaseList) {
this.checkedRowsCaseList.push(this.dataCaseList[i].field);
}
}
},
/**
* Unassign the selected columns from custm list
*/
unassignSelected() {
let temp;
let length = this.checkedRowsCaseList.length;
for (let i = 0; i < length; i++) {
temp = this.dataCaseList.find(
(x) => x.field === this.checkedRowsCaseList[i]
);
temp["set"] = false;
this.data.push(temp);
this.dataCaseList = this.dataCaseList.filter((item) => {
return item.field != this.checkedRowsCaseList[i];
});
}
this.checkedRowsCaseList = [];
},
/**
* Unassign all columns from custom list
*/
unassignAll() {
this.data = [...this.data, ...this.dataCaseList];
this.data.forEach(function (element) {
element.set = false;
});
this.dataCaseList = [];
},
/**
* Assign the selected row to custom list
*/
assignSelected() {
let temp;
let length = this.checkedRows.length;
for (let i = 0; i < length; i++) {
temp = this.data.find((x) => x.field === this.checkedRows[i]);
temp["set"] = true;
this.dataCaseList.push(temp);
this.data = this.data.filter((item) => {
return item.field != this.checkedRows[i];
});
}
this.checkedRows = [];
},
/**
* Assign all columns to custom list
*/
assignAll() {
this.dataCaseList = [...this.dataCaseList, ...this.data];
this.dataCaseList.forEach(function (element) {
element.set = true;
});
this.data = [];
},
/**
* On select icon handler
*/
onSelectIcon(data) {
this.params.iconList = data;
},
/**
* On change color handler
*/
onChangeColor(color) {
this.params.iconColor = color;
},
/**
* On change color screen handler
*/
onChangeColorScreen(color) {
this.params.iconColorScreen = color;
},
/**
* On Cancel event handler
*/
onCancel() {
this.$emit("closeSketch");
},
/**
* Find asynchronously in the server
* @param {string} query - string from the text field
*/
asyncFind(query) {
let self = this;
this.isLoading = true;
self.processes = [];
self.pmTablesOptions = [];
Api.reportTables({
search: query,
})
.then((response) => {
self.processes = [];
_.forEach(response.data, function(elem, key) {
self.pmTablesOptions.push({
label: elem.name,
value: elem.uid,
fields: elem.fields,
});
});
this.isLoading = false;
})
.catch((err) => {
console.error(err);
});
},
/**
* On select event handler in multiselect component
* @param {object} option
*/
onSelect(option) {
this.checkedRows = [];
this.data = option.fields;
this.dataCaseList = this.defaultCaseList;
},
/**
* On remove row event handler
* @param {object} row
*/
onRemoveRow(row) {
var temp = this.dataCaseList.find((x) => x.field === row.field);
if (temp) {
temp["set"] = false;
this.data.push(temp);
this.dataCaseList = this.dataCaseList.filter((item) => {
return item.field != row.field;
});
}
},
/**
* On remove row event handler
* @param {object} row
*/
onAddRow(row) {
var temp = this.data.find((x) => x.field === row.field);
if (temp) {
temp["set"] = true;
this.dataCaseList.push(temp);
this.data = this.data.filter((item) => {
return item.field != row.field;
});
}
},
/**
* On submit event handler
*/
onSubmit() {
let that = this;
this.isValidName = true;
this.isValidTable = true;
if (!this.params.name) {
this.isValidName = false;
return;
}
if (!this.pmTable) {
this.isValidTable = false;
return;
}
this.params.tableUid = this.pmTable.value;
this.params.columns = [...this.preparePostColumns(this.dataCaseList), ...this.preparePostColumns(this.data)];
this.params.type = this.module.key;
this.params.userId = window.config.userId;
if (this.params.id) {
delete this.params["tableName"];
Api.updateCaseList(this.params)
.then((response) => {
if (that.isPreview) {
that.$refs["modal-preview"].columns = that.getColumns();
that.$refs["modal-preview"].type = that.params.type;
that.$refs["modal-preview"].customCaseId = that.params.id;
that.$refs["modal-preview"].show();
that.isPreview = false;
} else {
this.$emit("closeSketch");
}
})
.catch((err) => {
this.makeToast('danger', this.$i18n.t('ID_ERROR'), err.response.statusText);
console.error(err);
});
} else {
Api.createCaseList(this.params)
.then((response) => {
if (that.isPreview) {
that.params.id = response.data.id;
that.$refs["modal-preview"].columns = that.getColumns();
that.$refs["modal-preview"].type = that.params.type;
that.$refs["modal-preview"].customCaseId = that.params.id;
that.$refs["modal-preview"].show();
that.isPreview = false;
} else {
this.$emit("closeSketch");
}
})
.catch((err) => {
this.makeToast('danger',this.$i18n.t('ID_ERROR') ,err.response.statusText);
console.error(err);
});
}
},
/**
* Prepares columns data to be sended to the server
* @param {array} collection
*/
preparePostColumns(collection){
let temp = [];
collection.forEach(function (value) {
temp.push({
field: value.field,
enableFilter: value.enableFilter || false,
set: value.set || false
})
});
return temp;
},
/**
* Tongle filter switcher
* @param {string} field
*/
onTongleFilter(field){
let objIndex = this.dataCaseList.findIndex((obj => obj.field === field));
this.dataCaseList[objIndex].enableFilter = !this.dataCaseList[objIndex].enableFilter
},
/**
* Make the toast component
* @param {string} variant
* @param {string} title
* @param {string} message
*/
makeToast(variant = null, title, message) {
this.$bvToast.toast(message, {
title: `${title || variant}`,
variant: variant,
solid: true
})
},
/**
* Get default Columns
* @param {string} type
*/
getDefaultColumns(type) {
let that = this;
Api.getDefault(type)
.then((response) => {
if (!that.params.columns) {
that.dataCaseList = response.data;
}
that.defaultCaseList = response.data;
})
.catch((e) => {
console.error(e);
})
},
/**
* Show modal preview
*/
showPreview() {
this.isPreview = true;
this.onSubmit();
},
/**
* Get columns to show in the preview
*/
getColumns() {
var columns = [],
auxColumn,
i;
for (i = 0; i < this.dataCaseList.length; i += 1) {
auxColumn = this.dataCaseList[i];
if (auxColumn.set) {
columns.push(auxColumn.field);
}
}
columns.push('actions');
columns.unshift('detail');
return columns
}
},
};
</script>
<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>
<style>
.verte {
position: relative;
display: flex;
justify-content: normal;
}
.control-panel {
height: 100%;
width: 8%;
float: left;
position: relative;
}
.vertical-center {
margin: 0;
position: absolute;
top: 50%;
-ms-transform: translateY(-50%);
transform: translateY(-50%);
}
.vertical-center > button {
width: 70%;
margin: 5px;
}
.invalid .multiselect__tags {
border-color: #f04124;
}
.invalid .typo__label {
color: #f04124;
}
</style>

View File

@@ -0,0 +1,108 @@
<template>
<div
id="home"
>
<div class="demo">
<div class="container" v-if="!showSketch">
<h5 >{{ $t("ID_CUSTOM_CASES_LISTS") }}</h5>
<div class="x_content">
<b-container fluid>
<b-tabs content-class="mt-3" @input="onInputTab">
<b-tab v-for="i in tabs" :key="'dyn-tab-' + i.key" :title="i.title" lazy>
<Tables :module="i.key"
@showSketch="onShowSketch"
@closeSketch="onCloseSketch"
/>
</b-tab>
</b-tabs>
</b-container>
</div>
</div>
<div class="container" v-if="showSketch">
<CaseListSketch
@showSketch="onShowSketch"
@closeSketch="onCloseSketch"
:module="tabModule"
:params="params"
/>
</div>
</div>
</div>
</template>
<script>
import Tables from "./Tables";
import CaseListSketch from "./CaseListSketch"
export default {
name: "CustomCaseList",
components: {
Tables,
CaseListSketch
},
data() {
return {
showSketch: false,
params: {},
tabModule: null,
tabs: [
{
key: "inbox",
title: this.$i18n.t("TO_DO")
},
{
key: "draft",
title: this.$i18n.t("ID_DRAFT")
},
{
key: "unassigned",
title: this.$i18n.t("ID_UNASSIGNED")
},
{
key: "paused",
title: this.$i18n.t("ID_PAUSED")
}
]
};
},
mounted() {
this.tabModule= this.tabs[0];
},
methods: {
/**
* Show sketch
*/
onShowSketch (params) {
this.showSketch = true;
this.params = params;
},
/**
* Close sketch
*/
onCloseSketch (params) {
this.showSketch = false;
},
/**
* On change input
*/
onInputTab(tabIndex){
this.tabModule= this.tabs[tabIndex];
}
}
};
</script>
<style lang="scss">
#home {
padding-left: 0px;
transition: 0.3s;
}
#home.collapsed {
padding-left: 50px;
}
#home.onmobile {
padding-left: 50px;
}
.container {
max-width: 1500px;
}
</style>

View File

@@ -0,0 +1,323 @@
<template>
<div id="people">
<ModalDeleteCaseList ref="modal-delete-list"></ModalDeleteCaseList>
<ModalPreview ref="modal-preview"></ModalPreview>
<ModalImport ref="modal-import"></ModalImport>
<button-fleft :data="newList"></button-fleft>
<button-fleft :data="importList"></button-fleft>
<v-server-table
:data="tableData"
:columns="columns"
:options="options"
ref="table"
>
<div slot="actions" slot-scope="props">
<div @click="updateDataEllipsis(props.row)">
<ellipsis :ref="`ellipsis-${props.row.id}`" v-if="dataEllipsis" :data="dataEllipsis"> </ellipsis>
</div>
</div>
<div slot="owner" slot-scope="props">
<OwnerCell :data="props.row.owner" />
</div>
</v-server-table>
</div>
</template>
<script>
import Api from "./Api/CaseList";
import ButtonFleft from "../../../components/home/ButtonFleft.vue";
import Ellipsis from "../../../components/utils/ellipsis.vue";
import utils from "../../../utils/utils";
import OwnerCell from "../../../components/vuetable/OwnerCell";
import ModalDeleteCaseList from "./../../Modals/ModalDeleteCaseList.vue";
import ModalPreview from "./../../Modals/ModalPreview.vue";
import ModalImport from "./../../Modals/ModalImport.vue";
import download from "downloadjs";
export default {
name: "Tables",
props: ["module"],
components: {
ButtonFleft,
Ellipsis,
OwnerCell,
ModalDeleteCaseList,
ModalPreview,
ModalImport,
},
data() {
return {
dataEllipsis: {
buttons: {}
},
showEllipsis: false,
newList: {
title: this.$i18n.t("New List"),
class: "btn-success",
onClick: () => {
this.$emit("showSketch", {
name: "",
description: "",
tableUid: "",
iconList: "far fa-check-circle",
iconColor: '#000000',
iconColorScreen: '#FFFFFF',
type: this.module
});
//TODO button
}
},
importList: {
title: this.$i18n.t("Import List"),
class: "btn-success",
onClick: () => {
this.importCustomCaseList();
}
},
columns: [
"name",
"process",
"tableName",
"owner",
"createDate",
"updateDate",
"actions"
],
tableData: [],
options: {
filterable: true,
headings: {
name: this.$i18n.t("ID_NAME"),
process: this.$i18n.t("ID_PROCESS"),
tableName: this.$i18n.t("ID_PM_TABLE"),
owner: this.$i18n.t("ID_OWNER"),
createDate: this.$i18n.t("ID_DATE_CREATED"),
updateDate: this.$i18n.t("ID_DATE_UPDATED"),
actions: ""
},
texts: {
count: this.$i18n.t("ID_SHOWING_FROM_RECORDS_COUNT"),
first: this.$i18n.t("ID_FIRST"),
last: this.$i18n.t("ID_LAST"),
filter: this.$i18n.t("ID_FILTER") + ":",
limit: this.$i18n.t("ID_RECORDS") + ":",
page: this.$i18n.t("ID_PAGE") + ":",
noResults: this.$i18n.t("ID_NO_MATCHING_RECORDS"),
},
requestFunction(data) {
return this.$parent.$parent.getCasesForVueTable(data);
},
},
customColumns: [],
};
},
methods: {
/**
* Get cases data by module
* @param {object} datas
* @returns {object}
*/
getCasesForVueTable(data) {
let that = this,
dt,
paged,
limit = data.limit,
start = data.page === 1 ? 0 : limit * (data.page - 1),
filters = {};
filters = {
offset: start,
limit: limit
};
if (data && data.query) {
filters["search"] = data.query;
}
_.forIn(this.filters, function (item, key) {
if(filters && item.value) {
filters[item.filterVar] = item.value;
}
});
return new Promise((resolutionFunc, rejectionFunc) => {
Api.getCaseList(filters, that.module)
.then((response) => {
dt = that.formatDataResponse(response.data.data);
resolutionFunc({
data: dt,
count: response.data.total
});
})
.catch((e) => {
rejectionFunc(e);
});
});
},
/**
* Format Response API TODO to grid inbox and columns
* @param {object} response
* @returns {object}
*/
formatDataResponse(response){
let that = this,
data = [],
userDataFormat;
_.forEach(response, (v) => {
userDataFormat = utils.userNameDisplayFormat({
userName: v.userName || "",
firstName: v.userFirstname || "",
lastName: v.userLastname || "",
format: window.config.FORMATS.format || null
});
v["owner"] = {
userAvatar: userDataFormat !== "" ? window.config.SYS_SERVER_AJAX +
window.config.SYS_URI +
`users/users_ViewPhotoGrid?pUID=${v.userId}` : "",
userInfo: userDataFormat || "",
userEmail: v.userEmail,
userId: v.userId,
userPosition: v.userPosition || ""
}
data.push(v);
});
return data;
},
/**
* Show modal to delete a custom case list
* @param {object} data
*/
showModalDelete(data) {
this.$refs["modal-delete-list"].data = data;
this.$refs["modal-delete-list"].show();
},
/**
* Show modal preview
* @param {object} data
*/
showPreview(data) {
this.$refs["modal-preview"].columns = this.getColumns(data);
this.$refs["modal-preview"].type = data.type;
this.$refs["modal-preview"].customCaseId = data.id;
this.$refs["modal-preview"].show();
},
/**
* Get columns to show in the preview
* @param {Object} data
* @returns {Array} columns
*/
getColumns(data) {
var columns = [],
auxColumn,
i;
for (i = 0; i < data.columns.length; i += 1) {
auxColumn = data.columns[i];
if (auxColumn.set) {
columns.push(auxColumn.field);
}
}
columns.push('actions');
columns.unshift('detail');
return columns
},
editCustomCaseList(data) {
this.$emit("showSketch", {
id: data.id,
name: data.name,
description: data.description,
tableUid: data.tableUid,
tableName: data.tableName,
iconList: data.iconList,
iconColor: data.iconColor,
iconColorScreen: data.iconColorScreen,
columns: data.columns,
enableFilter: data.enableFilter,
type: this.module
});
},
/**
* Export the Custom Case List in a json
* @param {object} data
*/
downloadCaseList(data) {
var fileName = data.name,
typeMime = "text/plain",
dataExport = [];
dataExport = this.filterDataToExport(data);
download(JSON.stringify(dataExport), fileName + ".json", typeMime);
},
/**
* Filter the sensible information to export
* @param {Array} data
*/
filterDataToExport(data) {
var dataExport = [];
dataExport.push({
type: data['type'],
name: data['name'],
description: data['description'],
tableUid: data['tableUid'],
tableName: data['tableName'],
columns: data['columns'],
userId: data['userId'],
iconList: data['iconList'],
iconColor: data['iconColor'],
iconColorScreen: data['iconColorScreen'],
createDate: data['createDate'],
updateDate: data['updateDate']
});
return dataExport;
},
/**
* Show options in the ellipsis
* @param {objec} data
*/
updateDataEllipsis(data) {
let that = this;
this.showEllipsis = !this.showEllipsis;
if (this.showEllipsis) {
this.dataEllipsis = {
buttons: {
open: {
name: "delete",
icon: "far fa-trash-alt",
color: "red",
fn: function() {
that.showModalDelete(data);
}
},
note: {
name: "edit",
icon: "far fa-edit",
fn: function() {
that.editCustomCaseList(data);
}
},
reassign: {
name: "download",
icon: "fas fa-arrow-circle-down",
fn: function() {
that.downloadCaseList(data);
}
},
preview: {
name: "preview",
icon: "fas fa-tv",
color: "green",
fn: function() {
that.showPreview(data);
}
}
}
}
}
},
importCustomCaseList() {
this.$refs["modal-import"].show();
}
}
};
</script>
<style>
.float-right {
padding-left: 1.5%;
}
</style>

View File

@@ -0,0 +1,53 @@
import Vue from "vue";
import VueRouter from "vue-router";
import VueSidebarMenu from "vue-sidebar-menu";
import VueI18n from 'vue-i18n';
import { BootstrapVue } from 'bootstrap-vue';
import { ServerTable, Event, ClientTable} from 'vue-tables-2';
import Sortable from 'sortablejs';
import "@fortawesome/fontawesome-free/css/all.css";
import 'bootstrap/dist/css/bootstrap-grid.css';
import 'bootstrap/dist/css/bootstrap.min.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'
import CustomCaseList from "./CustomCaseList";
import Verte from 'verte';
import 'verte/dist/verte.css';
// register component globally
Vue.component('verte', Verte);
Vue.use(VueRouter);
Vue.use(VueSidebarMenu);
Vue.use(BootstrapVue);
Vue.use(VueI18n);
Vue.use(ServerTable, {}, false, 'bootstrap3', {});
Vue.use(ClientTable, {}, false, 'bootstrap3', {});
window.ProcessMaker = {
apiClient: require('axios')
};
window.ProcessMaker.pluginBase = "/sysworkflow/en/neoclassic/viena/index.php";
window.ProcessMaker.apiClient.defaults.baseURL = '/sysworkflow/en/neoclassic/viena/index.php/api/';
window.ProcessMaker.SYS_SYS = "workflow";
window.ProcessMaker.SYS_LANG = "en";
window.ProcessMaker.SYS_SKIN = "neoclassic";
let messages = {};
messages[config.SYS_LANG] = config.TRANSLATIONS;
const i18n = new VueI18n({
locale: config.SYS_LANG, // set locale
messages, // set locale messages
});
// Define routes
const routes = [];
const router = new VueRouter({
routes, // short for `routes: routes`,
});
new Vue({
i18n,
// eslint-disable-line no-new
el: "#customCaseList",
router,
components: { Verte },
render: (h) => h(CustomCaseList),
});

View File

@@ -1,81 +1,14 @@
import _ from "lodash";
import axios from "axios";
const urlBase = "{server}/api/1.0/{workspace}{service}";
const services = {
AUTHENTICATE_USER: "/oauth2/token",
USER_DATA: "/light/user/data",
GET_MAIN_MENU_COUNTERS: "/light/counters",
GET_NOTES: "/cases/{app_uid}/notes/paged?files={files}",
GET_PROCESS_MAP: "/light/project/{prj_uid}/case/{app_uid}",
GET_LIST_UNASSIGNED: "/light/unassigned{suffix}",
GET_LISTS_PARTICIPATED: "/light/participated{suffix}",
GET_LISTS_DRAFT: "/light/draft{suffix}",
GET_LISTS_PAUSED: "/light/paused",
GET_LISTS_COMPLETED: "/light/completed",
GET_USERS_PICTURES: "/light/users/data",
FORMS_ARRAY: "/light/project/{pro_uid}/activity/{act_uid}/steps",
GET_NEW_CASES: "/case/start-cases?type_view=category",
GET_HISTORY_CASES: "/light/history/{app_uid}",
LOGOUT_USER: "/light/logout",
UPLOAD_LOCATION: "/light/case/{app_uid}/upload/location",
GET_FORM_ID_TO_UPLOAD: "/light/case/{app_uid}/upload",
UPLOAD_FILE: "/light/case/{app_uid}/upload/{app_doc_uid}",
GET_CASE_INFO: "/light/{type}/case/{app_uid}",
REQUEST_PAUSE_CASE: "/light/cases/{app_uid}/pause",
UNPAUSE_CASE: "/cases/{app_uid}/unpause",
CANCEL_CASE: "/cases/{app_uid}/cancel",
REQUEST_SYS_CONFIG: "/light/config",
REQUEST_SYS_CONFIG_V2: "/light/config?fileLimit=true",
ROUTE_CASE: "/light/cases/{app_uid}/route-case",
CLAIM_CASE: "/case/{app_uid}/claim",
GET_FILE_VERSIONS: "/cases/{app_uid}/input-document/{app_doc_uid}/versions",
REGISTER: "https:trial32.processmaker.com/syscolosa/en/neoclassic_pro/9893000714bdb2d52ecc317052629917/Trial_RequestPostMobile.php",
POST_NOTE: "/case/{app_uid}/note",
LAST_OPEN_INDEX: "/light/lastopenindex/case/{app_uid}",
REGISTER_WITH_GOOGLE_FAKE_URL: "fakeurl",
SIGN_IN_TO_PM_WITH_GOOGLE: "/authentication/gmail",
GET_CASE_VARIABLES: "/light/{app_uid}/variables?pro_uid={pro_uid}&act_uid={act_uid}&app_index={del_index}",
REGISTER_DEVICE_TOKEN_FOR_NOTIFICATIONS: "/light/notification",
UNREGISTER_DEVICE_TOKEN_FOR_NOTIFICATIONS: "/light/notification/{dev_uid}",
GET_ASSIGMENT_USERS: "/light/task/{act_uid}/case/{app_uid}/{del_index}/assignment",
GET_CASE_INPUT_FILES: "/cases/{app_uid}/input-documents",
GET_CASE_OUTPUT_FILES: "/cases/{app_uid}/output-documents",
DOWNLOAD_IMAGE_BASE64: "/light/case/{app_uid}/download64",
DOWNLOAD_INPUT_FILE: "/cases/{app_uid}/input-document/{app_doc_uid}/file?v=1",
DOWNLOAD_OUTPUT_FILE: "/cases/{app_uid}/output-document/{app_doc_uid}/file?v=1",
VERIFY_CASE_NOT_ROUTED: "/light/case/{app_uid}/{del_index}",
GET_FORM_DEFINITION: "/light/project/{prj_uid}/dynaform/{dyn_uid}",
GET_FORM_DEFINITION_PREPROCESSED: "/light/project/{prj_uid}/dynaformprocessed/{dyn_uid}?app_uid={app_uid}&del_index={del_index}",
START_CASE: "/light/process/{pro_uid}/task/{task_uid}/start-case",
GET_FORM_DEFINITIONS: "/cases/{app_uid}/input-document/{app_doc_uid}/file?v={version}",
SAVE_FORM_DATA: "/light/{app_uid}/variable?dyn_uid={dyn_uid}&del_index={del_index}",
EXECUTE_TRIGGERS_AFTER: "/light/process/{pro_uid}/task/{act_uid}/case/{app_uid}/step/{step_uid}/execute-trigger/after",
EXECUTE_QUERY: "/project/{prj_uid}/process-variable/{var_name}/execute-query",
EXECUTE_QUERY_SUGGEST: "/project/{prj_uid}/process-variable/{var_name}/execute-query-suggest",
CHECK: "/light/{listType}/check",
GET_NEXT_STEP: "/light/get-next-step/{app_uid}",
REQUEST_SQLITE_DATABASE_TABLES: "/pmtable?offline=1",
REQUEST_SQLITE_DATABASE_TABLES_DATA: "/pmtable/offline/data?compress=false",
MY_CASES: "/home/mycases",
TODO_LIST: "/home/todo",
DRAFT_LIST: "/home/draft",
PAUSED_LIST: "/home/paused",
UNASSIGNED_LIST: "/home/unassigned",
MY_FILTERS: "/cases/advanced-search/filters",
POST_MY_FILTERS: "/cases/advanced-search/filter",
PUT_MY_FILTERS: "/cases/advanced-search/filter/",
DELETE_MY_FILTERS: "/cases/advanced-search/filter/",
SEARCH: "/home/search",
PROCESSES: "/home/processes",
USERS: "/home/users",
TASKS: "/home/tasks",
DEBUG_STATUS: "/home/process-debug-status?processUid={prj_uid}"
};
class Api {
constructor(services) {
this.services = services;
}
export default {
getUrl(keys, service) {
let k;
let url = urlBase.replace(/{service}/, services[service]);
let url = urlBase.replace(/{service}/, this.services[service]);
let index;
let reg;
@@ -94,7 +27,7 @@ export default {
}
}
return url;
},
}
/**
* options.method = "post|get"
* options.service = "ENDPOINT ALIAS"
@@ -124,7 +57,7 @@ export default {
"Accept-Language": lang
}
});
},
}
get(options) {
let service = options.service || "",
params = options.params || {},
@@ -147,7 +80,7 @@ export default {
"Accept-Language": lang
}
});
},
}
post(options) {
let service = options.service || "",
params = options.params || {},
@@ -173,7 +106,7 @@ export default {
"Accept-Language": lang
}, headers)
});
},
}
postFiles(options) {
let service = options.service || "",
@@ -197,7 +130,7 @@ export default {
"Authorization": `Bearer ` + credentials.accessToken
}, headers)
});
},
}
delete(options) {
let service = options.service || "",
@@ -220,7 +153,7 @@ export default {
"Accept-Language": lang
}
});
},
}
put(options) {
let service = options.service || "",
params = options.params || {},
@@ -245,7 +178,7 @@ export default {
"Authorization": `Bearer ` + credentials.accessToken
}
});
},
}
/**
* Put action in AXIOS
* @param {*} options
@@ -259,6 +192,7 @@ export default {
url,
credentials = window.config.SYS_CREDENTIALS,
workspace = window.config.SYS_WORKSPACE,
lang = window.config.SYS_LANG,
server = window.config.SYS_SERVER_API;
url = this.getUrl(_.extend(keys, credentials, { server }, { workspace }), service);
@@ -275,4 +209,6 @@ export default {
}
});
}
};
}
export default Api;

View File

@@ -1,6 +1,7 @@
import axios from "axios";
import Api from "./Api.js";
import ApiInstance from "./Api.js";
import Services from "./Services";
let Api = new ApiInstance( Services );
export let caseNotes = {
post(data) {
var params = new FormData();

View File

@@ -1,5 +1,7 @@
import axios from "axios";
import Api from "./Api.js";
import ApiInstance from "./Api.js";
import Services from "./Services";
let Api = new ApiInstance( Services );
export let cases = {
myCases(data) {
@@ -16,25 +18,56 @@ export let cases = {
keys: {}
});
},
draft(data) {
inbox(data) {
let service = "INBOX_LIST",
keys = {};
if (data && data.id) {
service = "INBOX_CUSTOM_LIST";
keys["id"] = data.id;
}
return Api.get({
service: "DRAFT_LIST",
service,
params: data,
keys: {}
keys
});
},
draft(data) {
let service = "DRAFT_LIST",
keys = {};
if (data && data.id) {
service = "DRAFT_CUSTOM_LIST";
keys["id"] = data.id;
}
return Api.get({
service,
params: data,
keys
});
},
paused(data) {
let service = "PAUSED_LIST",
keys = {};
if (data && data.id) {
service = "PAUSED_CUSTOM_LIST";
keys["id"] = data.id;
}
return Api.get({
service: "PAUSED_LIST",
service,
params: data,
keys: {}
keys
});
},
unassigned(data) {
let service = "UNASSIGNED_LIST",
keys = {};
if (data && data.id) {
service = "UNASSIGNED_CUSTOM_LIST";
keys["id"] = data.id;
}
return Api.get({
service: "UNASSIGNED_LIST",
service,
params: data,
keys: {}
keys
});
},
summary(data) {
@@ -151,6 +184,26 @@ export let cases = {
window.config.SYS_URI +
`cases/ajaxListener`, params);
},
/**
* Pause case with endpoint
* @param {*} data
* @returns
*/
pauseCase(data) {
return Api.update({
service: "PAUSE_CASE",
data: {
unpaused_date: data.unpausedDate,
unpaused_time: data.unpausedTime,
index: data.DEL_INDEX,
reason: data.reasonPause,
sendMail: data.notifyUser
},
keys: {
app_uid: data.APP_UID
}
});
},
/**
* Unpause case with endpoint
* @param {*} data
@@ -159,7 +212,32 @@ export let cases = {
unpause(data) {
return Api.update({
service: "UNPAUSE_CASE",
data: {
index: data.DEL_INDEX
},
keys: {
app_uid: data.APP_UID
}
});
},
getUserReassign(data) {
return Api.get({
service: "REASSIGN_USERS",
data: {},
keys: {
task_uid: data.TAS_UID
}
});
},
reassingCase(data) {
return Api.update({
service: "REASSIGN_CASE",
data: {
usr_uid_target: data.userSelected,
del_index: data.DEL_INDEX,
reason: data.reasonReassign,
sendMail: data.notifyUser
},
keys: {
app_uid: data.APP_UID
}
@@ -248,6 +326,17 @@ export let cases = {
window.config.SYS_URI +
`cases/debug_triggers?r=${r}&_dc=${dc}`);
},
/**
* Make a search request to the Api service
* @param {object} dt - filter parameters
*/
listTotalCases(dt) {
return Api.get({
service: "LIST_TOTAL_CASES",
params: {},
keys: {}
})
},
};
export let casesHeader = {

View File

@@ -0,0 +1,24 @@
import ApiInstance from "./Api.js";
import Services from "./Services";
let Api = new ApiInstance( Services );
export let config = {
get(data) {
return Api.get({
service: "GET_CONFIG",
keys: data
});
},
post(data) {
return Api.post({
service: "CONFIG",
data: data
});
},
put(data) {
return Api.put({
service: "CONFIG",
data: data
});
},
};

View File

@@ -1,5 +1,7 @@
import axios from "axios";
import Api from "./Api.js";
import ApiInstance from "./Api.js";
import Services from "./Services";
let Api = new ApiInstance(Services);
export let filters = {
get(data) {
return Api.get({
@@ -40,8 +42,8 @@ export let filters = {
params.append("action", "startCase");
return axios.post(
window.config.SYS_SERVER_AJAX +
window.config.SYS_URI +
`cases/casesStartPage_Ajax.php`,
window.config.SYS_URI +
`cases/casesStartPage_Ajax.php`,
params
);
},
@@ -82,14 +84,31 @@ export let filters = {
keys: {},
});
},
/**
* Service to get the categories list
*/
categories(query) {
let pr = {
limit: 15,
offset: 0
};
if (query) {
pr["name"] = query;
}
return Api.get({
service: "CATEGORIES",
params: pr,
keys: {},
});
},
/**
* Service to get the users list
*/
userValues(query) {
return axios.post(
window.config.SYS_SERVER_AJAX +
window.config.SYS_URI +
`cases/casesList_Ajax?actionAjax=userValues&action=search`,
window.config.SYS_URI +
`cases/casesList_Ajax?actionAjax=userValues&action=search`,
{
query,
}

View File

@@ -25,5 +25,38 @@ export let menu = {
"Accept-Language": window.config.SYS_LANG
}
});
},
/**
* Get the counter of a specific task
* @param {string} task
* @returns
*/
getTooltip(task) {
return axios.get(
window.config.SYS_SERVER_API +
'/api/1.0/' +
window.config.SYS_WORKSPACE +
'/home/'+ task +'/counter', {
headers: {
'Authorization': 'Bearer ' + window.config.SYS_CREDENTIALS.accessToken,
"Accept-Language": window.config.SYS_LANG
}
});
},
/**
* Get the highlight
* @returns
*/
getHighlight() {
return axios.get(
window.config.SYS_SERVER_API +
'/api/1.0/' +
window.config.SYS_WORKSPACE +
'/home/tasks/highlight', {
headers: {
'Authorization': 'Bearer ' + window.config.SYS_CREDENTIALS.accessToken,
"Accept-Language": window.config.SYS_LANG
}
});
}
};

View File

@@ -1,4 +1,6 @@
import Api from "./Api.js";
import ApiInstance from "./Api.js";
import Services from "./Services";
let Api = new ApiInstance(Services);
export let process = {
list: {
@@ -10,5 +12,36 @@ export let process = {
keys: {}
});
}
}
},
totalCasesByProcess(dt) {
return Api.get({
service: "TOTAL_CASES_BY_PROCESS",
params: dt,
keys: {}
});
},
processCategories() {
return Api.fetch({
service: "PROCESS_CATEGORIES",
method: "get",
data: {},
keys: {}
});
},
totalCasesByRange(dt) {
return Api.get({
service: "TOTAL_CASES_BY_RANGE",
method: "get",
params: dt,
keys: {}
});
},
totalCasesByRisk(dt) {
return Api.get({
service: "CASES_RISK",
method: "get",
params: dt,
keys: {}
});
},
};

View File

@@ -0,0 +1,84 @@
export default {
AUTHENTICATE_USER: "/oauth2/token",
USER_DATA: "/light/user/data",
GET_MAIN_MENU_COUNTERS: "/light/counters",
GET_NOTES: "/cases/{app_uid}/notes/paged?files={files}",
GET_PROCESS_MAP: "/light/project/{prj_uid}/case/{app_uid}",
GET_LIST_UNASSIGNED: "/light/unassigned{suffix}",
GET_LISTS_PARTICIPATED: "/light/participated{suffix}",
GET_LISTS_DRAFT: "/light/draft{suffix}",
GET_LISTS_PAUSED: "/light/paused",
GET_LISTS_COMPLETED: "/light/completed",
GET_USERS_PICTURES: "/light/users/data",
FORMS_ARRAY: "/light/project/{pro_uid}/activity/{act_uid}/steps",
GET_NEW_CASES: "/case/start-cases?type_view=category",
GET_HISTORY_CASES: "/light/history/{app_uid}",
LOGOUT_USER: "/light/logout",
UPLOAD_LOCATION: "/light/case/{app_uid}/upload/location",
GET_FORM_ID_TO_UPLOAD: "/light/case/{app_uid}/upload",
UPLOAD_FILE: "/light/case/{app_uid}/upload/{app_doc_uid}",
GET_CASE_INFO: "/light/{type}/case/{app_uid}",
REQUEST_PAUSE_CASE: "/light/cases/{app_uid}/pause",
UNPAUSE_CASE: "/cases/{app_uid}/unpause",
CANCEL_CASE: "/cases/{app_uid}/cancel",
REQUEST_SYS_CONFIG: "/light/config",
REQUEST_SYS_CONFIG_V2: "/light/config?fileLimit=true",
ROUTE_CASE: "/light/cases/{app_uid}/route-case",
CLAIM_CASE: "/case/{app_uid}/claim",
GET_FILE_VERSIONS: "/cases/{app_uid}/input-document/{app_doc_uid}/versions",
REGISTER: "https:trial32.processmaker.com/syscolosa/en/neoclassic_pro/9893000714bdb2d52ecc317052629917/Trial_RequestPostMobile.php",
POST_NOTE: "/case/{app_uid}/note",
LAST_OPEN_INDEX: "/light/lastopenindex/case/{app_uid}",
REGISTER_WITH_GOOGLE_FAKE_URL: "fakeurl",
SIGN_IN_TO_PM_WITH_GOOGLE: "/authentication/gmail",
GET_CASE_VARIABLES: "/light/{app_uid}/variables?pro_uid={pro_uid}&act_uid={act_uid}&app_index={del_index}",
REGISTER_DEVICE_TOKEN_FOR_NOTIFICATIONS: "/light/notification",
UNREGISTER_DEVICE_TOKEN_FOR_NOTIFICATIONS: "/light/notification/{dev_uid}",
GET_ASSIGMENT_USERS: "/light/task/{act_uid}/case/{app_uid}/{del_index}/assignment",
GET_CASE_INPUT_FILES: "/cases/{app_uid}/input-documents",
GET_CASE_OUTPUT_FILES: "/cases/{app_uid}/output-documents",
DOWNLOAD_IMAGE_BASE64: "/light/case/{app_uid}/download64",
DOWNLOAD_INPUT_FILE: "/cases/{app_uid}/input-document/{app_doc_uid}/file?v=1",
DOWNLOAD_OUTPUT_FILE: "/cases/{app_uid}/output-document/{app_doc_uid}/file?v=1",
VERIFY_CASE_NOT_ROUTED: "/light/case/{app_uid}/{del_index}",
GET_FORM_DEFINITION: "/light/project/{prj_uid}/dynaform/{dyn_uid}",
GET_FORM_DEFINITION_PREPROCESSED: "/light/project/{prj_uid}/dynaformprocessed/{dyn_uid}?app_uid={app_uid}&del_index={del_index}",
START_CASE: "/light/process/{pro_uid}/task/{task_uid}/start-case",
GET_FORM_DEFINITIONS: "/cases/{app_uid}/input-document/{app_doc_uid}/file?v={version}",
SAVE_FORM_DATA: "/light/{app_uid}/variable?dyn_uid={dyn_uid}&del_index={del_index}",
EXECUTE_TRIGGERS_AFTER: "/light/process/{pro_uid}/task/{act_uid}/case/{app_uid}/step/{step_uid}/execute-trigger/after",
EXECUTE_QUERY: "/project/{prj_uid}/process-variable/{var_name}/execute-query",
EXECUTE_QUERY_SUGGEST: "/project/{prj_uid}/process-variable/{var_name}/execute-query-suggest",
CHECK: "/light/{listType}/check",
GET_NEXT_STEP: "/light/get-next-step/{app_uid}",
REQUEST_SQLITE_DATABASE_TABLES: "/pmtable?offline=1",
REQUEST_SQLITE_DATABASE_TABLES_DATA: "/pmtable/offline/data?compress=false",
MY_CASES: "/home/mycases",
TODO_LIST: "/home/todo",
DRAFT_LIST: "/home/draft",
PAUSED_LIST: "/home/paused",
UNASSIGNED_LIST: "/home/unassigned",
MY_FILTERS: "/cases/advanced-search/filters",
POST_MY_FILTERS: "/cases/advanced-search/filter",
PUT_MY_FILTERS: "/cases/advanced-search/filter/",
DELETE_MY_FILTERS: "/cases/advanced-search/filter/",
SEARCH: "/home/search",
PROCESSES: "/home/processes",
USERS: "/home/users",
TASKS: "/home/tasks",
CATEGORIES: "/home/categories",
DEBUG_STATUS: "/home/process-debug-status?processUid={prj_uid}",
LIST_TOTAL_CASES: "/metrics/list-total-cases",
TOTAL_CASES_BY_PROCESS:"/metrics/total-cases-by-process",
TOTAL_CASES_BY_RANGE:"/metrics/process-total-cases",
CASES_RISK:"/metrics/cases-risk",
CONFIG: "/home/config",
GET_CONFIG: "/home/config/{id}/{name}",
PAUSE_CASE: "/cases/{app_uid}/pause",
REASSIGN_CASE: "/cases/{app_uid}/reassign-case",
REASSIGN_USERS: "/light/userstoreassign/{task_uid}",
INBOX_CUSTOM_LIST: "/home/inbox/{id}",
DRAFT_CUSTOM_LIST: "/home/draft/{id}",
PAUSED_CUSTOM_LIST: "/home/paused/{id}",
UNASSIGNED_CUSTOM_LIST: "/home/unassigned/{id}"
};

View File

@@ -1,7 +1,7 @@
import { menu } from "./Menu";
import { cases, casesHeader } from "./Cases";
import { config } from "./Config";
import { caseNotes } from "./CaseNotes";
import { process } from "./Process";
import { filters } from "./Filters";
@@ -13,5 +13,6 @@ export default {
casesHeader,
process,
caseNotes,
filters
filters,
config
};

View File

@@ -0,0 +1,49 @@
<template>
<div class="pm-vue-card">
<div class="card pm-vue-card-inside" style="width: 20rem" @dblclick="dblClick">
<div class="card-body">
<slot> </slot>
</div>
</div>
</div>
</template>
<script>
export default {
name: "VueCardView",
props: ["options", "item"],
data() {
return {};
},
methods: {
classBtn(cls) {
return "btn btn-slim btn-force-radius v-btn-header " + cls;
},
/**
* Event handler dbl click
*/
dblClick(event){
this.options.dblClick(event, this.item, this.options);
}
},
};
</script>
<style>
.pm-vue-card {
display: inline-block;
padding: 0.7rem;
}
.pm-vue-card-inside {
border-left: solid lightseagreen;
color: #212529;
background-color: #f8f9fa;
}
.pm-vue-card-inside:hover {
background-color: #cfd9e4;
}
.card-body {
height: 266px;
overflow-x: hidden;
}
</style>

View File

@@ -0,0 +1,93 @@
<template>
<div class="pm-vue-card-view" :height="height">
<div class="pm-vue-card-view-container">
<div
class="pm-vue-card-view-body"
:style="{height: height + 'px'}"
>
<vue-card v-for="item in data" :key="item.id" :item="item" :options="options">
<b-row>
<b-col sm="9">
<slot
v-for="column in options.columns"
:name="column"
:item="item"
:column="column"
:headings="options.headings"
></slot>
<slot
name="send_by"
:item="item"
column="send_by"
:headings="options.headings"
></slot>
</b-col>
<b-col sm="3">
<slot
name="actions"
:item="item"
></slot>
</b-col>
</b-row>
</vue-card>
</div>
<div class="pm-vue-card-view-footer">
<a @click="viewMore" class="list-group-item">{{loadMore}}</a>
</div>
</div>
</div>
</template>
<script>
import VueCard from "./VueCard.vue";
import DefaultMixins from "./VueCardViewMixins";
export default {
name: "VueCardView",
mixins: [DefaultMixins],
components: {
VueCard,
},
props: ["options"],
data() {
return {
loadMore: this.$t("ID_LOAD_MORE")
};
},
mounted() {
this.filterOptions();
},
methods: {
classBtn(cls) {
return "btn btn-slim btn-force-radius v-btn-header " + cls;
},
/**
* Filter the column send_by
*/
filterOptions() {
this.options.columns = this.options.columns.filter(function(item) {
return item !== "send_by";
});
}
},
};
</script>
<style>
.pm-vue-card-view {
font-family: "proxima-nova", "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 0.9rem;
}
.pm-vue-card-view-body {
border: 1px solid rgba(0, 0, 0, 0.125);
padding-bottom: 5px;
margin-top: 5px;
overflow-y: auto;
}
.pm-vue-card-view-footer {
text-align: center;
line-height: 1.25;
}
</style>

View File

@@ -0,0 +1,57 @@
export default {
data() {
let that = this;
return {
height: 0,
config: {
page: 1
},
data: []
}
},
mounted: function () {
this.getData();
this.getBodyHeight();
},
methods: {
/**
* Get data similar to vue Table
*/
getData() {
let options = _.extend({}, this.config, this.options),
that = this;
this.options.requestFunction(options)
.then((data) => {
that.data = data.data;
})
.catch((e) => {
console.error(e);
});
},
/**
* Get data when press the button more view
*/
viewMore() {
let options = _.extend({}, this.config, this.options, { page: this.config.page + 1 }),
that = this;
this.options.requestFunctionViewMore(options)
.then((data) => {
if (data.data && data.data.length != 0) {
that.data = that.data.concat(data.data);
that.config.page += 1;
} else {
that.loadMore = that.$t("ID_NO_MORE_INFORMATION");
}
})
.catch((e) => {
console.error(e);
});
},
/**
* Return the height for Vue Card View body
*/
getBodyHeight() {
this.height = window.innerHeight - this.$root.$el.clientHeight;
}
}
}

View File

@@ -0,0 +1,48 @@
<template>
<div class="pm-vue-list">
<div class="card pm-vue-list-inside" @dblclick.prevent="dblClick">
<div class="list-body">
<slot> </slot>
</div>
</div>
</div>
</template>
<script>
export default {
name: "VueCardView",
props: ["item","options"],
data() {
return {};
},
methods: {
classBtn(cls) {
return "btn btn-slim btn-force-radius v-btn-header " + cls;
},
/**
* Event handler dbl click
*/
dblClick(event){
this.options.dblClick(event, this.item, this.options);
}
},
};
</script>
<style>
.pm-vue-list {
padding: 0.7rem 0.7rem 0rem 0.7rem;
}
.pm-vue-list-inside {
border-left: solid lightseagreen;
color: #212529;
background-color: #f8f9fa;
}
.pm-vue-list-inside:hover {
background-color: #cfd9e4;
}
.list-body {
height: 224px;
overflow-x: hidden;
}
</style>

View File

@@ -0,0 +1,96 @@
<template>
<div class="pm-vue-list-view" :height="height">
<div class="pm-vue-list-view-container">
<div
class="pm-vue-list-view-body"
:style="{height: height + 'px'}"
>
<vue-list v-for="item in data" :key="item.id" :item="item" :options="options">
<b-row>
<b-col sm="5">
<slot
v-for="column in options.columns"
:name="column"
:item="item"
:column="column"
:headings="options.headings"
ref="containerList"
></slot>
</b-col>
<b-col sm="5">
<slot
name="send_by"
:item="item"
column="send_by"
:headings="options.headings"
></slot>
</b-col>
<b-col sm="2">
<slot
name="actions"
:item="item"
></slot>
</b-col>
</b-row>
</vue-list>
</div>
<div class="pm-vue-list-view-footer">
<a @click="viewMore" class="list-group-item">{{ loadMore }}</a>
</div>
</div>
</div>
</template>
<script>
import VueList from "./VueList.vue";
import DefaultMixins from "./VueListViewMixins";
export default {
name: "VueListView",
mixins: [DefaultMixins],
components: {
VueList,
},
props: ["options"],
data() {
return {
loadMore: this.$t("ID_LOAD_MORE")
};
},
mounted() {
this.filterOptions();
},
methods: {
classBtn(cls) {
return "btn btn-slim btn-force-radius v-btn-header " + cls;
},
/**
* Filter the column send_by
*/
filterOptions() {
this.options.columns = this.options.columns.filter(function(item) {
return item !== "send_by";
});
}
},
};
</script>
<style>
.pm-vue-list-view {
font-family: "proxima-nova", "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 0.9rem;
}
.pm-vue-list-view-body {
border: 1px solid rgba(0, 0, 0, 0.125);
padding-bottom: 5px;
margin-top: 5px;
overflow-y: auto;
}
.pm-vue-list-view-footer {
text-align: center;
line-height: 1.25;
}
</style>

View File

@@ -0,0 +1,57 @@
export default {
data() {
let that = this;
return {
height: 0,
config: {
page: 1
},
data: []
}
},
mounted: function () {
this.getData();
this.getBodyHeight();
},
methods: {
/**
* Get data similar to vue Table
*/
getData() {
let options = _.extend({}, this.config, this.options),
that = this;
this.options.requestFunction(options)
.then((data) => {
that.data = data.data;
})
.catch((e) => {
console.error(e);
});
},
/**
* Get data when press the button more view
*/
viewMore() {
let options = _.extend({}, this.config, this.options, { page: this.config.page + 1 }),
that = this;
this.options.requestFunctionViewMore(options)
.then((data) => {
if (data.data && data.data.length != 0) {
that.data = that.data.concat(data.data);
that.config.page += 1;
} else {
that.loadMore = that.$t("ID_NO_MORE_INFORMATION");
}
})
.catch((e) => {
console.error(e);
});
},
/**
* Return the height for Vue list View body
*/
getBodyHeight() {
this.height = window.innerHeight - this.$root.$el.clientHeight;
}
}
}

View File

@@ -0,0 +1,79 @@
<template>
<div class="pm-multiview-header">
<div class="pm-multiview-header-title"></div>
<div class="pm-multiview-header-actions">
<b-row>
<b-col sm="8">
<div class="subtitle" v-if="dataSubtitle">
<h6>
{{ dataSubtitle.subtitle }}
<span>
<i :class="dataSubtitle.icon" v-bind:style="setIconColor"></i>
</span>
</h6>
</div>
</b-col>
<b-col sm="4" class="pm-multiview-header-actions-buttons">
<button
v-for="action in data.actions"
:key="action.id"
@click="action.onClick(action)"
class="pm-multiview-header-button"
:title="action.title"
>
<div>
<span>
<i :class="action.icon"></i>
</span>
</div>
</button>
</b-col>
</b-row>
</div>
</div>
</template>
<script>
export default {
name: "MultiviewHeader",
props: [
"data",
"dataSubtitle"
],
data() {
return {};
},
computed : {
/**
* Set color to icon defined from custom case list
*/
setIconColor() {
return {
color: this.dataSubtitle.color ? this.dataSubtitle.color : '#000'
};
}
},
methods: {
classBtn(cls) {
return "btn btn-slim btn-force-radius v-btn-header " + cls;
},
},
};
</script>
<style>
.pm-multiview-header {
margin-bottom: 7px;
}
.pm-multiview-header-actions-buttons {
text-align: end;
}
.pm-multiview-header-button {
background-color: transparent;
border-color: white;
font-size: 1.6rem;
color: #007bff;
display: inline-block;
padding: 0px 7px 0px 7px;
}
</style>

View File

@@ -0,0 +1,251 @@
<template>
<div class="rbt-icon-picker">
<b-button @click="popUpActive = true">
<i ref="icon" :class="icon"></i>
</b-button>
<div class="rip-popup-component" :style="popupActiveStyle">
<div class="rip-popup-bg"></div>
<div class="rip-popup">
<div class="rip-popup-content">
<div class="rip-search">
<div class="rip-input">
<label for="ripSearch" style="display: none;"
>{{$t("ID_SEARCH_FOR_ICON")}}</label
>
<input
id="ripSearch"
:placeholder="$t('ID_SEARCH_FOR_ICON')"
v-model="searchText"
@input="searchTextChanged"
/>
<span class="input-append">
<i class="fas fa-search"></i>
</span>
</div>
</div>
<div class="rip-content">
<div class="rip-not-found" v-show="loading">
<i class="fas fa-spinner fa-pulse"></i>
</div>
<div class="rip-icons" v-show="!loading">
<h4 class="icon-title">
{{$t('ID_REGULAR_ICONS')}}
</h4>
<p
style="text-align: center;"
v-if="regularIcons.length <= 0"
>
<i class="fas fa-eye-slash"></i>
{{$t('ID_SORRY_NO_ICONS')}}
</p>
<ul class="rip-row" v-if="regularIcons.length > 0">
<li
v-for="(icon, index) in regularIcons"
:key="index"
class="rip-col"
>
<div class="icon-content text-center">
<div
class="icon-el"
@click="selectIcon(icon, 'far')"
>
<i :class="`far fa-${icon}`"></i>
</div>
<div class="icon-title">
{{ icon }}
</div>
</div>
</li>
</ul>
<h4 class="icon-title">
{{$t('ID_BRAND_ICONS')}}
</h4>
<p
style="text-align: center;"
v-if="brandIcons.length <= 0"
>
<i class="fas fa-eye-slash"></i>
{{$t('ID_BRAND_ICONS_NOT_FOUND')}}
</p>
<ul class="rip-row" v-if="brandIcons.length > 0">
<li
v-for="(icon, index) in brandIcons"
:key="index"
class="rip-col"
>
<div class="icon-content text-center">
<div
class="icon-el"
@click="selectIcon(icon, 'fab')"
>
<i :class="`fab fa-${icon}`"></i>
</div>
<div class="icon-title">
{{ icon }}
</div>
</div>
</li>
</ul>
<h4 class="icon-title">
{{$t('ID_SOLID_ICONS')}}
</h4>
<p
style="text-align: center;"
v-if="solidIcons.length <= 0"
>
<i class="fas fa-eye-slash"></i>
{{$t('ID_SOLID_ICONS_NOT_FOUND')}}
</p>
<ul class="rip-row" v-if="solidIcons.length > 0">
<li
v-for="(icon, index) in solidIcons"
:key="index"
class="rip-col"
>
<div class="icon-content text-center">
<div
class="icon-el"
@click="selectIcon(icon, 'fas')"
>
<i :class="`fas fa-${icon}`"></i>
</div>
<div class="icon-title">
{{ icon }}
</div>
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import ripIcons from "./assets/icons";
export default {
name: "VueAwesomeIconPicker",
props: {
button: {
type: String,
default: "Pick A Icon",
},
color: {
type: String,
default: "black",
},
title: {
type: String,
default: "Vue Awesome Icon Picker",
},
iconPreview: {
type: Boolean,
default: true,
},
default: {
type: String,
default: null,
},
},
data() {
return {
loading: false,
allIcons: {
brand: [],
regular: [],
solid: [],
},
popUpActive: false,
icon: null,
searchText: "",
searchIconNotFound: false,
};
},
watch: {
color() {
console.log("colores");
},
},
methods: {
/**
* Handler select icon
*/
selectIcon(icon, type) {
this.icon = `${type} fa-${icon}`;
this.popUpActive = false;
this.$emit("selected", this.icon);
},
/**
* Handler search text changed
*/
searchTextChanged() {
this.searchIcon(this.searchText);
},
/**
* Set default icons
*/
setDefaultIcons() {
this.allIcons.brand = ripIcons.brand;
this.allIcons.regular = ripIcons.regular;
this.allIcons.solid = ripIcons.solid;
},
/**
* Serach icons handler
*/
searchIcon(txt) {
this.loading = true;
if (txt && txt.length > 0) {
setTimeout(() => {
this.loading = false;
}, 950);
txt = txt.toLowerCase();
Object.keys(ripIcons).forEach((key) => {
setTimeout(() => {
let icons = ripIcons[key].filter(
(ico) => ico.indexOf(txt) > -1
);
if (icons && icons.length > 0) {
this.allIcons[key] = icons;
} else {
this.allIcons[key] = [];
}
}, 320);
});
} else {
setTimeout(() => {
this.setDefaultIcons();
this.loading = false;
}, 950);
}
},
},
created() {
this.setDefaultIcons();
if (this.default) {
this.icon = this.default;
}
},
computed: {
popupActiveStyle() {
return !this.popUpActive ? "display: none;" : "";
},
brandIcons() {
return this.loading ? [] : this.allIcons.brand;
},
solidIcons() {
return this.loading ? [] : this.allIcons.solid;
},
regularIcons() {
return this.loading ? [] : this.allIcons.regular;
},
},
};
</script>
<style lang="scss" scoped>
@import "./assets/RbtIconPicker";
</style>

View File

@@ -0,0 +1,239 @@
.rbt-icon-picker {
.icon-preview {
font-size: 22px;
padding: 10px 20px 0;
display: inline-block;
}
.picker-btn {
color: #fff;
background: #339af0;
padding: 12px 25px;
border: 0;
border-radius: 2px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.02em;
cursor: pointer;
transition: all .25s ease-in;
&:hover {
background: #2c89d6;
}
}
}
.rip-popup-component {
text-align: center;
z-index: 5999999;
transition: all .2s;
width: 100%;
height: 100%;
position: fixed;
top: 0;
left: 0;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
opacity: 1;
.rip-popup-bg {
width: 100%;
background: rgba(0,0,0,.4);
position: absolute;
top: 0;
height: 100%;
z-index: 10;
transition: all .25s ease;
opacity: 1;
left: 0;
}
.rip-popup {
transition: all .2s;
z-index: 100;
margin: 10px;
width: calc(100% - 30px);
height: calc(100% - 30px);
border-radius: 6px;
box-shadow: 0 5px 20px 0 rgba(0,0,0,.1);
background: #f8f9fa;
animation: rebound .3s;
.rip-popup-header {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
background: rgba(0,0,0,.05);
border-radius: 5px 5px;
position: relative;
h2 {
transition: all .23s ease .1s;
padding: 8px 8px 8px 12px;
font-size: 18px;
text-align: center;
width: 100%;
}
span {
background: #ffffff;
transition: all .23s ease .1s;
position: relative;
padding: 8px;
cursor: pointer;
box-shadow: 0 5px 20px 0 rgba(0,0,0,.1);
border-radius: 5px;
color: rgba(0,0,0,.6);
transform: translate(8px,-8px);
line-height: 16px;
font-size: 30px;
&:hover {
box-shadow: 0 0 0 0 rgba(0,0,0,.1);
transform: translate(5px,-5px);
}
}
}
.rip-popup-content {
padding: 14px;
font-size: 14px;
transition: all .23s ease .1s;
overflow: auto;
max-height: calc(100vh - 100px);
margin-top: 5px;
margin-bottom: 5px;
.rip-search {
.rip-input {
display: flex;
-webkit-box-align: start;
-ms-flex-align: start;
align-items: flex-start;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
position: relative;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
padding-bottom: 20px;
border-bottom: 1px dashed #e5e5e5;
margin-bottom: 20px;
input {
width: 100% !important;
transition: all .1s ease-in-out;
padding: 16px 48px 16px 24px;
font-size: 25px;
border: 2px solid #dee2e6;
box-shadow: inset 0 0.25rem 0.125rem 0 rgba(0,0,0,0.05);
color: #495057;
border-radius: 4px;
&::placeholder {
color: #c9cbcd;
}
}
span {
position: absolute;
right: 25px;
font-size: 28px;
color: #caccce;
opacity: 0.4;
}
}
}
.rip-content {
width: 100%;
.rip-not-found {
min-height: 75vh;
display: flex;
align-items: center;
align-self: center;
align-content: center;
min-width: 100%;
text-align: center;
svg {
margin: 0 auto;
font-size: 50px;
color: #adb5bd;
}
}
h4.icon-title {
font-size: 20px;
text-transform: uppercase;
letter-spacing: 0.03em;
margin-bottom: 25px;
}
.rip-row {
width: 100%;
display: flex;
flex-wrap: wrap;
margin: 0;
padding: 0;
.rip-col {
text-align: center;
padding: 0 0 16px;
width: 25%;
list-style: none;
.icon-content {
border-radius: 3px;
transition: all 0.5s cubic-bezier(0.165, 0.84, 0.44, 1);
transform: translateZ(0);
.icon-el {
padding: 8px;
font-size: 35px;
font-weight: 900;
color: #495057;
cursor: pointer;
transition: all ;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
&:hover {
color: #fff;
background: #339af0;
}
}
.icon-title {
padding: 8px 4px;
font-size: 13px;
color: #adb5bd;
&:hover {
color: #495057;
}
}
&:hover {
background: #fff;
box-shadow: 0 0.25rem 0.125rem 0 rgba(0,0,0,0.05);
}
}
@media (min-width: 576px) {
width: 20%;
}
@media (min-width: 768px) {
width: 16.6667%;
}
@media (min-width: 1200px) {
width: 11.1111%;
}
}
}
}
}
}
}
@keyframes rebound {
0% {
-webkit-transform: scale(.9);
transform: scale(.9);
}
50% {
-webkit-transform: scale(1.08);
transform: scale(1.08);
}
100% {
-webkit-transform: scale(1);
transform: scale(1);
}
}

View File

@@ -0,0 +1,437 @@
const brand = [
'500px',
'accessible-icon',
'accusoft',
'acquisitions-incorporated',
'adn',
'adobe',
'adversal',
'affiliatetheme',
'airbnb',
'algolia',
'alipay',
'amazon',
'amazon-pay',
'amilia',
'android',
'angellist',
'angrycreative',
'angular',
'app-store',
'app-store-ios',
'apper',
'apple',
'apple-pay',
'artstation',
'asymmetrik',
'atlassian',
'audible',
'autoprefixer',
'avianex',
'aviato',
'aws',
'bandcamp',
'battle-net',
'behance',
'behance-square',
'bimobject',
'bitbucket',
'bitcoin',
'bity',
'black-tie',
'blackberry',
'blogger',
'blogger-b',
'bluetooth',
'bluetooth-b',
'bootstrap',
'btc',
'buffer',
'buromobelexperte',
'buy-n-large',
'buysellads',
'canadian-maple-leaf',
'cc-amazon-pay',
'cc-amex',
'cc-apple-pay',
'cc-diners-club',
'cc-discover',
'cc-jcb',
'cc-mastercard',
'cc-paypal',
'cc-stripe',
'cc-visa',
'centercode',
'centos',
'chrome',
'chromecast',
'cloudscale',
'cloudsmith',
'cloudversify',
'codepen',
'codiepie',
'confluence',
'connectdevelop',
'contao',
'cotton-bureau',
'cpanel',
'creative-commons',
'creative-commons-by',
'creative-commons-nc',
'creative-commons-nc-eu',
'creative-commons-nc-jp',
'creative-commons-nd',
'creative-commons-pd',
'creative-commons-pd-alt',
'creative-commons-remix',
'creative-commons-sa',
'creative-commons-sampling',
'creative-commons-sampling-plus',
'creative-commons-share',
'creative-commons-zero',
'critical-role',
'css3',
'css3-alt',
'cuttlefish',
'd-and-d',
'd-and-d-beyond',
'dashcube',
'delicious',
'deploydog',
'deskpro',
'dev',
'deviantart',
'dhl',
'diaspora',
'digg',
'digital-ocean',
'discord',
'discourse',
'dochub',
'docker',
'draft2digital',
'dribbble',
'dribbble-square',
'dropbox',
'drupal',
'dyalog',
'earlybirds',
'ebay',
'edge',
'elementor',
'ello',
'ember',
'empire',
'envira',
'erlang',
'ethereum',
'etsy',
'evernote',
'expeditedssl',
'facebook',
'facebook-f',
'facebook-messenger',
'facebook-square',
'fantasy-flight-games',
'fedex',
'fedora',
'figma',
'firefox',
'first-order',
'first-order-alt',
'firstdraft',
'flickr',
'flipboard',
'fly',
'font-awesome',
'font-awesome-alt',
'font-awesome-flag',
'fonticons',
'fonticons-fi',
'fort-awesome',
'fort-awesome-alt',
'forumbee',
'foursquare',
'free-code-camp',
'freebsd',
'fulcrum',
'galactic-republic',
'galactic-senate',
'get-pocket',
'gg',
'gg-circle',
'git',
'git-alt',
'git-square',
'github',
'github-alt',
'github-square',
'gitkraken',
'gitlab',
'gitter',
'glide',
'glide-g',
'gofore',
'goodreads',
'goodreads-g',
'google',
'google-drive',
'google-play',
'google-plus',
'google-plus-g',
'google-plus-square',
'google-wallet',
'gratipay',
'grav',
'gripfire',
'grunt',
'gulp',
'hacker-news',
'hacker-news-square',
'hackerrank',
'hips',
'hire-a-helper',
'hooli',
'hornbill',
'hotjar',
'houzz',
'html5',
'hubspot',
'imdb',
'instagram',
'intercom',
'internet-explorer',
'invision',
'ioxhost',
'itch-io',
'itunes',
'itunes-note',
'java',
'jedi-order',
'jenkins',
'jira',
'joget',
'joomla',
'js',
'js-square',
'jsfiddle',
'kaggle',
'keybase',
'keycdn',
'kickstarter',
'kickstarter-k',
'korvue',
'laravel',
'lastfm',
'lastfm-square',
'leanpub',
'less',
'line',
'linkedin',
'linkedin-in',
'linode',
'linux',
'lyft',
'magento',
'mailchimp',
'mandalorian',
'markdown',
'mastodon',
'maxcdn',
'mdb',
'medapps',
'medium',
'medium-m',
'medrt',
'meetup',
'megaport',
'mendeley',
'microsoft',
'mix',
'mixcloud',
'mizuni',
'modx',
'monero',
'napster',
'neos',
'nimblr',
'node',
'node-js',
'npm',
'ns8',
'nutritionix',
'odnoklassniki',
'odnoklassniki-square',
'old-republic',
'opencart',
'openid',
'opera',
'optin-monster',
'orcid',
'osi',
'page4',
'pagelines',
'palfed',
'patreon',
'paypal',
'penny-arcade',
'periscope',
'phabricator',
'phoenix-framework',
'phoenix-squadron',
'php',
'pied-piper',
'pied-piper-alt',
'pied-piper-hat',
'pied-piper-pp',
'pinterest',
'pinterest-p',
'pinterest-square',
'playstation',
'product-hunt',
'pushed',
'python',
'qq',
'quinscape',
'quora',
'r-project',
'raspberry-pi',
'ravelry',
'react',
'reacteurope',
'readme',
'rebel',
'red-river',
'reddit',
'reddit-alien',
'reddit-square',
'redhat',
'renren',
'replyd',
'researchgate',
'resolving',
'rev',
'rocketchat',
'rockrms',
'safari',
'salesforce',
'sass',
'schlix',
'scribd',
'searchengin',
'sellcast',
'sellsy',
'servicestack',
'shirtsinbulk',
'shopware',
'simplybuilt',
'sistrix',
'sith',
'sketch',
'skyatlas',
'skype',
'slack',
'slack-hash',
'slideshare',
'snapchat',
'snapchat-ghost',
'snapchat-square',
'soundcloud',
'sourcetree',
'speakap',
'speaker-deck',
'spotify',
'squarespace',
'stack-exchange',
'stack-overflow',
'stackpath',
'staylinked',
'steam',
'steam-square',
'steam-symbol',
'sticker-mule',
'strava',
'stripe',
'stripe-s',
'studiovinari',
'stumbleupon',
'stumbleupon-circle',
'superpowers',
'supple',
'suse',
'swift',
'symfony',
'teamspeak',
'telegram',
'telegram-plane',
'tencent-weibo',
'the-red-yeti',
'themeco',
'themeisle',
'think-peaks',
'trade-federation',
'trello',
'tripadvisor',
'tumblr',
'tumblr-square',
'twitch',
'twitter',
'twitter-square',
'typo3',
'uber',
'ubuntu',
'uikit',
'umbraco',
'uniregistry',
'untappd',
'ups',
'usb',
'usps',
'ussunnah',
'vaadin',
'viacoin',
'viadeo',
'viadeo-square',
'viber',
'vimeo',
'vimeo-square',
'vimeo-v',
'vine',
'vk',
'vnv',
'vuejs',
'waze',
'weebly',
'weibo',
'weixin',
'whatsapp',
'whatsapp-square',
'whmcs',
'wikipedia-w',
'windows',
'wix',
'wizards-of-the-coast',
'wolf-pack-battalion',
'wordpress',
'wordpress-simple',
'wpbeginner',
'wpexplorer',
'wpforms',
'wpressr',
'xbox',
'xing',
'xing-square',
'y-combinator',
'yahoo',
'yammer',
'yandex',
'yandex-international',
'yarn',
'yelp',
'yoast',
'youtube',
'youtube-square',
'zhihu'
];
export default brand;

View File

@@ -0,0 +1,7 @@
import solid from "./solid";
import regular from "./regular";
import brand from "./brand";
const icons = { solid, brand, regular };
export default icons;

View File

@@ -0,0 +1,155 @@
const regular = [
'address-book',
'address-card',
'angry',
'arrow-alt-circle-down',
'arrow-alt-circle-left',
'arrow-alt-circle-right',
'arrow-alt-circle-up',
'bell',
'bell-slash',
'bookmark',
'building',
'calendar',
'calendar-alt',
'calendar-check',
'calendar-minus',
'calendar-plus',
'calendar-times',
'caret-square-down',
'caret-square-left',
'caret-square-right',
'caret-square-up',
'chart-bar',
'check-circle',
'check-square',
'circle',
'clipboard',
'clock',
'clone',
'closed-captioning',
'comment',
'comment-alt',
'comment-dots',
'comments',
'compass',
'copy',
'copyright',
'credit-card',
'dizzy',
'dot-circle',
'edit',
'envelope',
'envelope-open',
'eye',
'eye-slash',
'file',
'file-alt',
'file-archive',
'file-audio',
'file-code',
'file-excel',
'file-image',
'file-pdf',
'file-powerpoint',
'file-video',
'file-word',
'flag',
'flushed',
'folder',
'folder-open',
'frown',
'frown-open',
'futbol',
'gem',
'grimace',
'grin',
'grin-alt',
'grin-beam',
'grin-beam-sweat',
'grin-hearts',
'grin-squint',
'grin-squint-tears',
'grin-stars',
'grin-tears',
'grin-tongue',
'grin-tongue-squint',
'grin-tongue-wink',
'grin-wink',
'hand-lizard',
'hand-paper',
'hand-peace',
'hand-point-down',
'hand-point-left',
'hand-point-right',
'hand-point-up',
'hand-pointer',
'hand-rock',
'hand-scissors',
'hand-spock',
'handshake',
'hdd',
'heart',
'hospital',
'hourglass',
'id-badge',
'id-card',
'image',
'images',
'keyboard',
'kiss',
'kiss-beam',
'kiss-wink-heart',
'laugh',
'laugh-beam',
'laugh-squint',
'laugh-wink',
'lemon',
'life-ring',
'lightbulb',
'list-alt',
'map',
'meh',
'meh-blank',
'meh-rolling-eyes',
'minus-square',
'money-bill-alt',
'moon',
'newspaper',
'object-group',
'object-ungroup',
'paper-plane',
'pause-circle',
'play-circle',
'plus-square',
'question-circle',
'registered',
'sad-cry',
'sad-tear',
'save',
'share-square',
'smile',
'smile-beam',
'smile-wink',
'snowflake',
'square',
'star',
'star-half',
'sticky-note',
'stop-circle',
'sun',
'surprise',
'thumbs-down',
'thumbs-up',
'times-circle',
'tired',
'trash-alt',
'user',
'user-circle',
'window-close',
'window-maximize',
'window-minimize',
'window-restore'
];
export default regular;

View File

@@ -0,0 +1,962 @@
const solid = [
'ad',
'address-book',
'address-card',
'adjust',
'air-freshener',
'align-center',
'align-justify',
'align-left',
'align-right',
'allergies',
'ambulance',
'american-sign-language-interpreting',
'anchor',
'angle-double-down',
'angle-double-left',
'angle-double-right',
'angle-double-up',
'angle-down',
'angle-left',
'angle-right',
'angle-up',
'angry',
'ankh',
'apple-alt',
'archive',
'archway',
'arrow-alt-circle-down',
'arrow-alt-circle-left',
'arrow-alt-circle-right',
'arrow-alt-circle-up',
'arrow-circle-down',
'arrow-circle-left',
'arrow-circle-right',
'arrow-circle-up',
'arrow-down',
'arrow-left',
'arrow-right',
'arrow-up',
'arrows-alt',
'arrows-alt-h',
'arrows-alt-v',
'assistive-listening-systems',
'asterisk',
'at',
'atlas',
'atom',
'audio-description',
'award',
'baby',
'baby-carriage',
'backspace',
'backward',
'bacon',
'balance-scale',
'balance-scale-left',
'balance-scale-right',
'ban',
'band-aid',
'barcode',
'bars',
'baseball-ball',
'basketball-ball',
'bath',
'battery-empty',
'battery-full',
'battery-half',
'battery-quarter',
'battery-three-quarters',
'bed',
'beer',
'bell',
'bell-slash',
'bezier-curve',
'bible',
'bicycle',
'biking',
'binoculars',
'biohazard',
'birthday-cake',
'blender',
'blender-phone',
'blind',
'blog',
'bold',
'bolt',
'bomb',
'bone',
'bong',
'book',
'book-dead',
'book-medical',
'book-open',
'book-reader',
'bookmark',
'border-all',
'border-none',
'border-style',
'bowling-ball',
'box',
'box-open',
'boxes',
'braille',
'brain',
'bread-slice',
'briefcase',
'briefcase-medical',
'broadcast-tower',
'broom',
'brush',
'bug',
'building',
'bullhorn',
'bullseye',
'burn',
'bus',
'bus-alt',
'business-time',
'calculator',
'calendar',
'calendar-alt',
'calendar-check',
'calendar-day',
'calendar-minus',
'calendar-plus',
'calendar-times',
'calendar-week',
'camera',
'camera-retro',
'campground',
'candy-cane',
'cannabis',
'capsules',
'car',
'car-alt',
'car-battery',
'car-crash',
'car-side',
'caret-down',
'caret-left',
'caret-right',
'caret-square-down',
'caret-square-left',
'caret-square-right',
'caret-square-up',
'caret-up',
'carrot',
'cart-arrow-down',
'cart-plus',
'cash-register',
'cat',
'certificate',
'chair',
'chalkboard',
'chalkboard-teacher',
'charging-station',
'chart-area',
'chart-bar',
'chart-line',
'chart-pie',
'check',
'check-circle',
'check-double',
'check-square',
'cheese',
'chess',
'chess-bishop',
'chess-board',
'chess-king',
'chess-knight',
'chess-pawn',
'chess-queen',
'chess-rook',
'chevron-circle-down',
'chevron-circle-left',
'chevron-circle-right',
'chevron-circle-up',
'chevron-down',
'chevron-left',
'chevron-right',
'chevron-up',
'child',
'church',
'circle',
'circle-notch',
'city',
'clinic-medical',
'clipboard',
'clipboard-check',
'clipboard-list',
'clock',
'clone',
'closed-captioning',
'cloud',
'cloud-download-alt',
'cloud-meatball',
'cloud-moon',
'cloud-moon-rain',
'cloud-rain',
'cloud-showers-heavy',
'cloud-sun',
'cloud-sun-rain',
'cloud-upload-alt',
'cocktail',
'code',
'code-branch',
'coffee',
'cog',
'cogs',
'coins',
'columns',
'comment',
'comment-alt',
'comment-dollar',
'comment-dots',
'comment-medical',
'comment-slash',
'comments',
'comments-dollar',
'compact-disc',
'compass',
'compress',
'compress-arrows-alt',
'concierge-bell',
'cookie',
'cookie-bite',
'copy',
'copyright',
'couch',
'credit-card',
'crop',
'crop-alt',
'cross',
'crosshairs',
'crow',
'crown',
'crutch',
'cube',
'cubes',
'cut',
'database',
'deaf',
'democrat',
'desktop',
'dharmachakra',
'diagnoses',
'dice',
'dice-d20',
'dice-d6',
'dice-five',
'dice-four',
'dice-one',
'dice-six',
'dice-three',
'dice-two',
'digital-tachograph',
'directions',
'divide',
'dizzy',
'dna',
'dog',
'dollar-sign',
'dolly',
'dolly-flatbed',
'donate',
'door-closed',
'door-open',
'dot-circle',
'dove',
'download',
'drafting-compass',
'dragon',
'draw-polygon',
'drum',
'drum-steelpan',
'drumstick-bite',
'dumbbell',
'dumpster',
'dumpster-fire',
'dungeon',
'edit',
'egg',
'eject',
'ellipsis-h',
'ellipsis-v',
'envelope',
'envelope-open',
'envelope-open-text',
'envelope-square',
'equals',
'eraser',
'ethernet',
'euro-sign',
'exchange-alt',
'exclamation',
'exclamation-circle',
'exclamation-triangle',
'expand',
'expand-arrows-alt',
'external-link-alt',
'external-link-square-alt',
'eye',
'eye-dropper',
'eye-slash',
'fan',
'fast-backward',
'fast-forward',
'fax',
'feather',
'feather-alt',
'female',
'fighter-jet',
'file',
'file-alt',
'file-archive',
'file-audio',
'file-code',
'file-contract',
'file-csv',
'file-download',
'file-excel',
'file-export',
'file-image',
'file-import',
'file-invoice',
'file-invoice-dollar',
'file-medical',
'file-medical-alt',
'file-pdf',
'file-powerpoint',
'file-prescription',
'file-signature',
'file-upload',
'file-video',
'file-word',
'fill',
'fill-drip',
'film',
'filter',
'fingerprint',
'fire',
'fire-alt',
'fire-extinguisher',
'first-aid',
'fish',
'fist-raised',
'flag',
'flag-checkered',
'flag-usa',
'flask',
'flushed',
'folder',
'folder-minus',
'folder-open',
'folder-plus',
'font',
'football-ball',
'forward',
'frog',
'frown',
'frown-open',
'funnel-dollar',
'futbol',
'gamepad',
'gas-pump',
'gavel',
'gem',
'genderless',
'ghost',
'gift',
'gifts',
'glass-cheers',
'glass-martini',
'glass-martini-alt',
'glass-whiskey',
'glasses',
'globe',
'globe-africa',
'globe-americas',
'globe-asia',
'globe-europe',
'golf-ball',
'gopuram',
'graduation-cap',
'greater-than',
'greater-than-equal',
'grimace',
'grin',
'grin-alt',
'grin-beam',
'grin-beam-sweat',
'grin-hearts',
'grin-squint',
'grin-squint-tears',
'grin-stars',
'grin-tears',
'grin-tongue',
'grin-tongue-squint',
'grin-tongue-wink',
'grin-wink',
'grip-horizontal',
'grip-lines',
'grip-lines-vertical',
'grip-vertical',
'guitar',
'h-square',
'hamburger',
'hammer',
'hamsa',
'hand-holding',
'hand-holding-heart',
'hand-holding-usd',
'hand-lizard',
'hand-middle-finger',
'hand-paper',
'hand-peace',
'hand-point-down',
'hand-point-left',
'hand-point-right',
'hand-point-up',
'hand-pointer',
'hand-rock',
'hand-scissors',
'hand-spock',
'hands',
'hands-helping',
'handshake',
'hanukiah',
'hard-hat',
'hashtag',
'hat-cowboy',
'hat-cowboy-side',
'hat-wizard',
'heading',
'headphones',
'headphones-alt',
'headset',
'heart',
'heart-broken',
'heartbeat',
'helicopter',
'highlighter',
'hiking',
'hippo',
'history',
'hockey-puck',
'holly-berry',
'home',
'horse',
'horse-head',
'hospital',
'hospital-alt',
'hospital-symbol',
'hot-tub',
'hotdog',
'hotel',
'hourglass',
'hourglass-end',
'hourglass-half',
'hourglass-start',
'house-damage',
'hryvnia',
'i-cursor',
'ice-cream',
'icicles',
'icons',
'id-badge',
'id-card',
'id-card-alt',
'igloo',
'image',
'images',
'inbox',
'indent',
'industry',
'infinity',
'info',
'info-circle',
'italic',
'jedi',
'joint',
'journal-whills',
'kaaba',
'key',
'keyboard',
'khanda',
'kiss',
'kiss-beam',
'kiss-wink-heart',
'kiwi-bird',
'landmark',
'language',
'laptop',
'laptop-code',
'laptop-medical',
'laugh',
'laugh-beam',
'laugh-squint',
'laugh-wink',
'layer-group',
'leaf',
'lemon',
'less-than',
'less-than-equal',
'level-down-alt',
'level-up-alt',
'life-ring',
'lightbulb',
'link',
'lira-sign',
'list',
'list-alt',
'list-ol',
'list-ul',
'location-arrow',
'lock',
'lock-open',
'long-arrow-alt-down',
'long-arrow-alt-left',
'long-arrow-alt-right',
'long-arrow-alt-up',
'low-vision',
'luggage-cart',
'magic',
'magnet',
'mail-bulk',
'male',
'map',
'map-marked',
'map-marked-alt',
'map-marker',
'map-marker-alt',
'map-pin',
'map-signs',
'marker',
'mars',
'mars-double',
'mars-stroke',
'mars-stroke-h',
'mars-stroke-v',
'mask',
'medal',
'medkit',
'meh',
'meh-blank',
'meh-rolling-eyes',
'memory',
'menorah',
'mercury',
'meteor',
'microchip',
'microphone',
'microphone-alt',
'microphone-alt-slash',
'microphone-slash',
'microscope',
'minus',
'minus-circle',
'minus-square',
'mitten',
'mobile',
'mobile-alt',
'money-bill',
'money-bill-alt',
'money-bill-wave',
'money-bill-wave-alt',
'money-check',
'money-check-alt',
'monument',
'moon',
'mortar-pestle',
'mosque',
'motorcycle',
'mountain',
'mouse',
'mouse-pointer',
'mug-hot',
'music',
'network-wired',
'neuter',
'newspaper',
'not-equal',
'notes-medical',
'object-group',
'object-ungroup',
'oil-can',
'om',
'otter',
'outdent',
'pager',
'paint-brush',
'paint-roller',
'palette',
'pallet',
'paper-plane',
'paperclip',
'parachute-box',
'paragraph',
'parking',
'passport',
'pastafarianism',
'paste',
'pause',
'pause-circle',
'paw',
'peace',
'pen',
'pen-alt',
'pen-fancy',
'pen-nib',
'pen-square',
'pencil-alt',
'pencil-ruler',
'people-carry',
'pepper-hot',
'percent',
'percentage',
'person-booth',
'phone',
'phone-alt',
'phone-slash',
'phone-square',
'phone-square-alt',
'phone-volume',
'photo-video',
'piggy-bank',
'pills',
'pizza-slice',
'place-of-worship',
'plane',
'plane-arrival',
'plane-departure',
'play',
'play-circle',
'plug',
'plus',
'plus-circle',
'plus-square',
'podcast',
'poll',
'poll-h',
'poo',
'poo-storm',
'poop',
'portrait',
'pound-sign',
'power-off',
'pray',
'praying-hands',
'prescription',
'prescription-bottle',
'prescription-bottle-alt',
'print',
'procedures',
'project-diagram',
'puzzle-piece',
'qrcode',
'question',
'question-circle',
'quidditch',
'quote-left',
'quote-right',
'quran',
'radiation',
'radiation-alt',
'rainbow',
'random',
'receipt',
'record-vinyl',
'recycle',
'redo',
'redo-alt',
'registered',
'remove-format',
'reply',
'reply-all',
'republican',
'restroom',
'retweet',
'ribbon',
'ring',
'road',
'robot',
'rocket',
'route',
'rss',
'rss-square',
'ruble-sign',
'ruler',
'ruler-combined',
'ruler-horizontal',
'ruler-vertical',
'running',
'rupee-sign',
'sad-cry',
'sad-tear',
'satellite',
'satellite-dish',
'save',
'school',
'screwdriver',
'scroll',
'sd-card',
'search',
'search-dollar',
'search-location',
'search-minus',
'search-plus',
'seedling',
'server',
'shapes',
'share',
'share-alt',
'share-alt-square',
'share-square',
'shekel-sign',
'shield-alt',
'ship',
'shipping-fast',
'shoe-prints',
'shopping-bag',
'shopping-basket',
'shopping-cart',
'shower',
'shuttle-van',
'sign',
'sign-in-alt',
'sign-language',
'sign-out-alt',
'signal',
'signature',
'sim-card',
'sitemap',
'skating',
'skiing',
'skiing-nordic',
'skull',
'skull-crossbones',
'slash',
'sleigh',
'sliders-h',
'smile',
'smile-beam',
'smile-wink',
'smog',
'smoking',
'smoking-ban',
'sms',
'snowboarding',
'snowflake',
'snowman',
'snowplow',
'socks',
'solar-panel',
'sort',
'sort-alpha-down',
'sort-alpha-down-alt',
'sort-alpha-up',
'sort-alpha-up-alt',
'sort-amount-down',
'sort-amount-down-alt',
'sort-amount-up',
'sort-amount-up-alt',
'sort-down',
'sort-numeric-down',
'sort-numeric-down-alt',
'sort-numeric-up',
'sort-numeric-up-alt',
'sort-up',
'spa',
'space-shuttle',
'spell-check',
'spider',
'spinner',
'splotch',
'spray-can',
'square',
'square-full',
'square-root-alt',
'stamp',
'star',
'star-and-crescent',
'star-half',
'star-half-alt',
'star-of-david',
'star-of-life',
'step-backward',
'step-forward',
'stethoscope',
'sticky-note',
'stop',
'stop-circle',
'stopwatch',
'store',
'store-alt',
'stream',
'street-view',
'strikethrough',
'stroopwafel',
'subscript',
'subway',
'suitcase',
'suitcase-rolling',
'sun',
'superscript',
'surprise',
'swatchbook',
'swimmer',
'swimming-pool',
'synagogue',
'sync',
'sync-alt',
'syringe',
'table',
'table-tennis',
'tablet',
'tablet-alt',
'tablets',
'tachometer-alt',
'tag',
'tags',
'tape',
'tasks',
'taxi',
'teeth',
'teeth-open',
'temperature-high',
'temperature-low',
'tenge',
'terminal',
'text-height',
'text-width',
'th',
'th-large',
'th-list',
'theater-masks',
'thermometer',
'thermometer-empty',
'thermometer-full',
'thermometer-half',
'thermometer-quarter',
'thermometer-three-quarters',
'thumbs-down',
'thumbs-up',
'thumbtack',
'ticket-alt',
'times',
'times-circle',
'tint',
'tint-slash',
'tired',
'toggle-off',
'toggle-on',
'toilet',
'toilet-paper',
'toolbox',
'tools',
'tooth',
'torah',
'torii-gate',
'tractor',
'trademark',
'traffic-light',
'train',
'tram',
'transgender',
'transgender-alt',
'trash',
'trash-alt',
'trash-restore',
'trash-restore-alt',
'tree',
'trophy',
'truck',
'truck-loading',
'truck-monster',
'truck-moving',
'truck-pickup',
'tshirt',
'tty',
'tv',
'umbrella',
'umbrella-beach',
'underline',
'undo',
'undo-alt',
'universal-access',
'university',
'unlink',
'unlock',
'unlock-alt',
'upload',
'user',
'user-alt',
'user-alt-slash',
'user-astronaut',
'user-check',
'user-circle',
'user-clock',
'user-cog',
'user-edit',
'user-friends',
'user-graduate',
'user-injured',
'user-lock',
'user-md',
'user-minus',
'user-ninja',
'user-nurse',
'user-plus',
'user-secret',
'user-shield',
'user-slash',
'user-tag',
'user-tie',
'user-times',
'users',
'users-cog',
'utensil-spoon',
'utensils',
'vector-square',
'venus',
'venus-double',
'venus-mars',
'vial',
'vials',
'video',
'video-slash',
'vihara',
'voicemail',
'volleyball-ball',
'volume-down',
'volume-mute',
'volume-off',
'volume-up',
'vote-yea',
'vr-cardboard',
'walking',
'wallet',
'warehouse',
'water',
'wave-square',
'weight',
'weight-hanging',
'wheelchair',
'wifi',
'wind',
'window-close',
'window-maximize',
'window-minimize',
'window-restore',
'wine-bottle',
'wine-glass',
'wine-glass-alt',
'won-sign',
'wrench',
'x-ray',
'yen-sign',
'yin-yang'
];
export default solid;

View File

@@ -21,9 +21,11 @@
<script>
import api from "./../../api/index";
import CustomSidebarMenuItem from "./CustomSidebarMenuItem";
export default {
name: "CustomSidebar",
props: ["menu"],
data() {
return {
collapsed: false,
@@ -61,8 +63,8 @@ export default {
onItemClick(event, item, node) {
this.$emit("OnClickSidebarItem", { item });
},
/**
* On resize event handler id the windows is resized
/**
* On resize event handler id the windows is resized
* collase and isMobile proerty will be updated
*/
onResize() {
@@ -74,7 +76,7 @@ export default {
this.collapsed = false;
}
}
},
}
};
</script>

View File

@@ -0,0 +1,26 @@
<template>
<component
:is="icon.element ? icon.element : 'i'"
class="vsm--icon"
:class="
typeof icon === 'string' || icon instanceof String
? icon
: icon.class
"
v-bind="icon.attributes"
>
{{ icon.text }}
</component>
</template>
<script>
export default {
name: "CustomSidebarMenuIcon",
props: {
icon: {
type: [String, Object],
default: "",
},
},
};
</script>

View File

@@ -0,0 +1,557 @@
<template>
<div id="my-container">
<div
v-if="item.header && !isItemHidden"
class="vsm--header"
:class="item.class"
v-bind="item.attributes"
>
{{ item.title }}
<b-icon
:icon="item.icon || ''"
@click="item.onClick(item) || function() {}"
></b-icon>
</div>
<div
v-else-if="!isItemHidden"
class="vsm--item"
:class="[{ 'vsm--item_open': show }]"
@mouseover="mouseOverEvent"
@mouseout="mouseOutEvent"
>
<custom-sidebar-menu-link
:item="item"
:class="itemLinkClass"
:attributes="item.attributes"
@click.native="clickEvent"
>
<custom-sidebar-menu-icon
v-if="item.icon && !isMobileItem"
:icon="item.icon"
v-bind:style="setIconColor"
/>
<transition name="fade-animation" :appear="isMobileItem">
<template
v-if="
(isCollapsed && !isFirstLevel) ||
!isCollapsed ||
isMobileItem
"
>
<span class="vsm--title">
<template v-if="itemHasChild">
<custom-tooltip
:data="item"
ref="tooltip"
></custom-tooltip>
</template>
<template v-else>
<span> {{ item.title }} </span>
</template>
<b-icon
v-if="item.sortable"
:icon="item.sortIcon"
@click="onClickSortSettings"
></b-icon>
</span>
</template>
</transition>
<template
v-if="
(isCollapsed && !isFirstLevel) ||
!isCollapsed ||
isMobileItem
"
>
<div
v-if="itemHasChild"
class="vsm--arrow"
:class="[
{ 'vsm--arrow_open': show },
{ 'vsm--arrow_slot': $slots['dropdown-icon'] },
]"
>
<slot name="dropdown-icon" />
</div>
</template>
</custom-sidebar-menu-link>
<template v-if="itemHasChild">
<template
v-if="
(isCollapsed && !isFirstLevel) ||
!isCollapsed ||
isMobileItem
"
>
<transition
:appear="isMobileItem"
name="expand"
@enter="expandEnter"
@afterEnter="expandAfterEnter"
@beforeLeave="expandBeforeLeave"
>
<div
v-if="show"
class="vsm--dropdown"
:class="isMobileItem && 'vsm--dropdown_mobile-item'"
:style="isMobileItem && mobileItemStyle.dropdown"
>
<div class="vsm--list">
<custom-sidebar-menu-item
v-for="(subItem, index) in item.child"
:key="index"
:item="subItem"
:level="level + 1"
:show-child="showChild"
:rtl="rtl"
:is-collapsed="isCollapsed"
>
<slot
slot="dropdown-icon"
name="dropdown-icon"
/>
</custom-sidebar-menu-item>
</div>
</div>
</transition>
</template>
</template>
<b-modal
ref="modal"
v-if="item.sortable"
id="my-modal"
static
title="Custom Case List Order"
>
<draggable
:list="item.child"
:disabled="!enabled"
class="list-group"
ghost-class="ghost"
@end="checkMove"
@start="dragging = true"
handle=".handle"
>
<div
class="list-group-item"
v-for="element in item.child"
:key="element.title"
>
<b-row>
<b-col
><b-icon icon="check-circle"></b-icon>
</b-col>
<b-col cols="9">{{ element.title }}</b-col>
<b-col
><i class="fa fa-align-justify handle"></i
></b-col>
</b-row>
</div>
</draggable>
<template #modal-footer="{ cancel }">
<b-button size="sm" variant="danger" @click="cancel()">
{{ $t("ID_CLOSE") }}
</b-button>
</template>
</b-modal>
</div>
</div>
</template>
<script>
import draggable from "vuedraggable";
import CustomSidebarMenuLink from "./CustomSidebarMenuLink";
import CustomSidebarMenuIcon from "./CustomSidebarMenuIcon";
import CustomTooltip from "./../utils/CustomTooltip.vue";
import eventBus from "./../../home/EventBus/eventBus";
export default {
name: "CustomSidebarMenuItem",
props: {
item: {
type: Object,
required: true,
},
level: {
type: Number,
default: 1,
},
isMobileItem: {
type: Boolean,
default: false,
},
mobileItem: {
type: Object,
default: null,
},
activeShow: {
type: Object,
default: null,
},
showChild: {
type: Boolean,
default: false,
},
showOneChild: {
type: Boolean,
default: false,
},
rtl: {
type: Boolean,
default: false,
},
disableHover: {
type: Boolean,
default: false,
},
mobileItemStyle: {
type: Object,
default: null,
},
},
components: {
draggable,
CustomSidebarMenuLink,
CustomSidebarMenuIcon,
CustomTooltip,
},
data() {
return {
enabled: true,
dragging: false,
itemShow: false,
itemHover: false,
exactActive: false,
active: false,
titleHover: "",
};
},
mounted() {
this.setHighlight();
},
computed: {
isCollapsed() {
return this.$parent.isCollapsed;
},
itemLinkClass() {
return [
"vsm--link",
!this.isMobileItem ? `vsm--link_level-${this.level}` : "",
{ "vsm--link_mobile-item": this.isMobileItem },
{ "vsm--link_hover": this.hover },
{ "vsm--link_active": this.active },
{ "vsm--link_exact-active": this.exactActive },
{ "vsm--link_disabled": this.item.disabled },
this.item.class,
];
},
draggingInfo() {
return this.dragging ? "under drag" : "";
},
show: {
get() {
if (!this.itemHasChild) return false;
if (this.showChild || this.isMobileItem) return true;
return this.itemShow;
},
set(show) {
if (this.showOneChild) {
show
? this.emitActiveShow(this.item)
: this.emitActiveShow(null);
}
this.itemShow = show;
},
},
isFirstLevel() {
return this.level === 1;
},
itemHasChild() {
return !!(this.item.child && this.item.child.length > 0);
},
isItemHidden() {
if (this.isCollapsed) {
if (
this.item.hidden &&
this.item.hiddenOnCollapse === undefined
) {
return true;
} else {
return this.item.hiddenOnCollapse === true;
}
} else {
return this.item.hidden === true;
}
},
/**
* Set color to icon defined from custom case list
*/
setIconColor() {
return {
color: this.item.color ? this.item.color : '#fff'
};
},
},
watch: {
$route() {
setTimeout(() => {
if (this.item.header || this.item.component) return;
this.initState();
}, 1);
},
item(newItem, item) {
this.emitItemUpdate(newItem, item);
},
activeShow() {
this.itemShow = this.item === this.activeShow;
},
},
created() {
this.initState();
},
methods: {
/**
* set the highlight
*/
setHighlight() {
let that = this;
eventBus.$on('highlight', (data) => {
var i;
for (i = 0; i < data.length; i += 1) {
if (that.item.page && that.item.page === data[i].id) {
if (that.$refs.tooltip) {
that.$refs.tooltip.setHighlight()
}
}
}
});
},
/**
* Match the route to ensure the correct location
* @param {string} href
* @param {string} exactPath
* @return {boolean}
*/
matchRoute({ href, exactPath }) {
if (!href) return false;
if (this.$router) {
const { route } = this.$router.resolve(href);
return exactPath
? route.path === this.$route.path
: this.matchExactRoute(href);
} else {
return exactPath
? href === window.location.pathname
: this.matchExactRoute(href);
}
},
/**
* Match the exact route with the current location
* @param {string} href
* @return {boolean}
*/
matchExactRoute(href) {
if (!href) return false;
if (this.$router) {
const { route } = this.$router.resolve(href);
return route.fullPath === this.$route.fullPath;
} else {
return (
href ===
window.location.pathname +
window.location.search +
window.location.hash
);
}
},
/**
* Check if the child is active
* @param {object} child
* @return {boolean}
*/
isChildActive(child) {
if (!child) return false;
return child.some((item) => {
return this.isLinkActive(item);
});
},
/**
* Validate if the Alias is active
* @param {object} item
* @return {boobleam}
*/
isAliasActive(item) {
if (item.alias) {
const current = this.$router
? this.$route.fullPath
: window.location.pathname +
window.location.search +
window.location.hash;
if (Array.isArray(item.alias)) {
return item.alias.some((alias) => {
return pathToRegexp(alias).test(current);
});
} else {
return pathToRegexp(item.alias).test(current);
}
}
return false;
},
/**
* Validate if the link is active
* @param {object} item
* @return {boolean}
*/
isLinkActive(item) {
return (
this.matchRoute(item) ||
this.isChildActive(item.child) ||
this.isAliasActive(item)
);
},
/**
* Ensurre if the link exact is active
* @param {object} item
* @return {boolean}
*/
isLinkExactActive(item) {
return this.matchExactRoute(item.href);
},
/**
* Initialize the state of the menu item
*/
initState() {
this.initActiveState();
},
/**
* Initalize the active state of the menu item
*/
initActiveState() {
this.active = this.isLinkActive(this.item);
this.exactActive = this.isLinkExactActive(this.item);
},
/**
* Initialize and show active state menu item
*/
initShowState() {
if (!this.itemHasChild || this.showChild) return;
if (
(this.showOneChild && this.active && !this.show) ||
(this.active && !this.show)
) {
this.show = true;
} else if (this.showOneChild && !this.active && this.show) {
this.show = false;
}
},
/**
* Handler to check if the item is moving
* @param {object} e
*/
checkMove: function(e) {
let aux = this.item.child.splice(e.newIndex, 1);
this.item.child.splice(e.newIndex, 0, aux[0]);
this.emitItemUpdate(this.item, this.item);
eventBus.$emit("sort-menu", this.item.child);
},
/**
* Click event Handler
* @param {object} event
*/
clickEvent(event) {
if (this.item.disabled) return;
if (!this.item.href) {
event.preventDefault();
}
this.emitItemClick(event, this.item, this);
this.emitMobileItem(event, event.currentTarget.offsetParent);
if (!this.itemHasChild || this.showChild || this.isMobileItem)
return;
if (!this.item.href || this.exactActive) {
this.show = !this.show;
}
},
/**
* Mouse over event handler
* @param {object} event
*/
mouseOverEvent(event) {
if (this.item.disabled) return;
event.stopPropagation();
this.itemHover = true;
if (!this.disableHover) {
this.emitMobileItem(event, event.currentTarget);
}
},
/**
* Mouse out event handler
* @param {object} event
*/
mouseOutEvent(event) {
event.stopPropagation();
this.itemHover = false;
},
/**
* Expand sidebar menu item handler
* @param {object} el
*/
expandEnter(el) {
el.style.height = el.scrollHeight + "px";
},
/**
* Expand after enter menu item handler
* @param {object} el
*/
expandAfterEnter(el) {
el.style.height = "auto";
},
/**
* Expand before leace handler
* @param {object} el
*/
expandBeforeLeave(el) {
if (this.isCollapsed && this.isFirstLevel) {
el.style.display = "none";
return;
}
el.style.height = el.scrollHeight + "px";
},
/**
* Emit Mobile item handler
* @param {object} event
* @param {object} itemEl
*/
emitMobileItem(event, itemEl) {
if (this.hover) return;
if (!this.isCollapsed || !this.isFirstLevel || this.isMobileItem)
return;
this.$parent.$emit("unset-mobile-item", true);
setTimeout(() => {
if (this.$parent.mobileItem !== this.item) {
this.$parent.$emit("set-mobile-item", {
item: this.item,
itemEl,
});
}
if (event.type === "click" && !this.itemHasChild) {
this.$parent.$emit("unset-mobile-item", false);
}
}, 0);
},
/**
* Click Sort settings event handler
* @param {object} event
*/
onClickSortSettings(event) {
event.preventDefault();
event.stopPropagation();
this.$refs["modal"].show();
},
},
inject: ["emitActiveShow", "emitItemClick", "emitItemUpdate"],
};
</script>

View File

@@ -0,0 +1,42 @@
<template>
<component
:is="tag"
v-bind="[isRouterLink ? { to: href } : { href: href }, attributes]"
:tabindex="item.disabled && -1"
:target="target"
>
<slot />
</component>
</template>
<script>
export default {
name: "CustomSidebarMenuLink",
props: {
item: {
type: Object,
required: true
},
attributes: {
type: Object,
default: null
},
},
computed: {
isRouterLink() {
return !!this.$router && this.item.href && !this.item.external;
},
tag() {
return this.isRouterLink ? "router-link" : "a";
},
href() {
if (!this.item.href) return "#";
return this.item.href;
},
target() {
if (this.item.external) return "_blank";
return "_self";
}
}
};
</script>

View File

@@ -195,6 +195,8 @@ import CasePriority from "./popovers/CasePriority.vue";
import CaseStatus from "./popovers/CaseStatus.vue";
import CurrentUser from "./popovers/CurrentUser.vue";
import TaskTitle from "./popovers/TaskTitle.vue";
import Participation from "./popovers/Participation.vue";
import ProcessCategory from "./popovers/ProcessCategory.vue";
import api from "./../../api/index";
export default {
@@ -209,7 +211,9 @@ export default {
CaseStatus,
CurrentUser,
DateFilter,
TaskTitle
TaskTitle,
Participation,
ProcessCategory
},
data() {
return {
@@ -219,11 +223,11 @@ export default {
{
type: "CaseNumber",
id: "caseNumber",
title: `${this.$i18n.t('ID_FILTER')}: ${this.$i18n.t('ID_IUD')}`,
optionLabel: this.$i18n.t('ID_IUD'),
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_A_RANGE_TO_CASES_TO_SEARCH'),
tagText: "",
tagPrefix: this.$i18n.t('ID_IUD'),
tagPrefix: this.$i18n.t('ID_SEARCH_BY_CASE_NUMBER'),
items:[
{
id: "filterCases",
@@ -231,15 +235,15 @@ export default {
}
],
makeTagText: function (params, data) {
return `${params.tagPrefix}: ${data[0].value}`;
return `${params.tagPrefix} ${data[0].value}`;
}
},
{
type: "CaseTitle",
id: "caseTitle",
title: `${this.$i18n.t('ID_FILTER')}: ${this.$i18n.t('ID_CASE_TITLE')}`,
optionLabel: this.$i18n.t('ID_CASE_TITLE'),
tagPrefix: this.$i18n.t('ID_CASE_TITLE'),
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:[
@@ -249,14 +253,14 @@ export default {
}
],
makeTagText: function (params, data) {
return `${this.tagPrefix}: ${data[0].value}`;
return `${this.tagPrefix} ${data[0].value}`;
}
},
{
type: "caseStatus",
id: "CaseStatus",
title: `${this.$i18n.t('ID_FILTER')}: ${this.$i18n.t('ID_CASE_STATUS')}`,
optionLabel: this.$i18n.t('ID_STATUS'),
title: `${this.$i18n.t('ID_FILTER')}: ${this.$i18n.t('ID_BY_STATUS')}`,
optionLabel: this.$i18n.t('ID_BY_STATUS'),
detail: this.$i18n.t('ID_PLEASE_SELECT_THE_STATUS_FOR_THE_SEARCH'),
tagText: "",
tagPrefix: this.$i18n.t('ID_SEARCH_BY_STATUS'),
@@ -291,11 +295,11 @@ export default {
{
type: "ProcessName",
id: "processName",
title: `${this.$i18n.t('ID_FILTER')}: ${this.$i18n.t('ID_PROCESS_NAME')}`,
optionLabel: this.$i18n.t('ID_PROCESS_NAME'),
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_PROCESS_NAME'),
tagPrefix: this.$i18n.t('ID_SEARCH_BY_PROCESS_NAME'),
items:[
{
id: "process",
@@ -311,8 +315,8 @@ export default {
{
type: "TaskTitle",
id: "taskTitle",
title: `${this.$i18n.t('ID_FILTER')}: ${this.$i18n.t('ID_TASK_NAME')}`,
optionLabel: this.$i18n.t('ID_TASK'),
title: `${this.$i18n.t('ID_FILTER')}: ${this.$i18n.t('ID_BY_TASK')}`,
optionLabel: this.$i18n.t('ID_BY_TASK'),
detail: "",
tagText: "",
tagPrefix: this.$i18n.t('ID_SEARCH_BY_TASK_NAME'),
@@ -331,15 +335,15 @@ export default {
{
type: "CurrentUser",
id: "currentUser",
title: `${this.$i18n.t('ID_FILTER')}: ${this.$i18n.t('ID_CURRENT_USER')}`,
optionLabel: this.$i18n.t('ID_CURRENT_USER'),
title: `${this.$i18n.t('ID_FILTER')}: ${this.$i18n.t('ID_BY_CURRENT_USER')}`,
optionLabel: this.$i18n.t('ID_BY_CURRENT_USER'),
detail: "",
placeholder: this.$i18n.t('ID_USER_NAME'),
tagText: "",
tagPrefix: this.$i18n.t('ID_USER'),
tagPrefix: this.$i18n.t('ID_SEARCH_BY_CURRENT_USER'),
items:[
{
id: "user",
id: "sendBy",
value: "",
options: [],
placeholder: this.$i18n.t('ID_USER_NAME')
@@ -376,9 +380,9 @@ export default {
{
type: "DateFilter",
id: "finishDate",
title: `${this.$i18n.t('ID_FILTER')}: ${this.$i18n.t('ID_FINISH_DATE')}`,
optionLabel: this.$i18n.t('ID_FINISH_DATE'),
detail: this.$i18n.t('Please set a range of cases Finish Date to search:'),
title: `${this.$i18n.t('ID_FILTER')}: ${this.$i18n.t('ID_BY_FINISH_DATE')}`,
optionLabel: this.$i18n.t('ID_BY_FINISH_DATE'),
detail: this.$i18n.t('ID_PLEASE_SET_A_RANGE_OF_CASES_FINISH_DATE_TO_SEARCH'),
tagText: "",
tagPrefix: this.$i18n.t('ID_SEARCH_BY_FINISH_DATE'),
items:[
@@ -396,8 +400,66 @@ export default {
makeTagText: function (params, data) {
return `${params.tagPrefix} ${data[0].value} - ${data[1].value}`;
}
},
{
type: "Participation",
id: "participation",
title: `${this.$i18n.t('ID_FILTER')}: ${this.$i18n.t('ID_BY_PARTICIPATION')}`,
optionLabel: this.$i18n.t('ID_BY_PARTICIPATION'),
detail: this.$i18n.t('ID_CHECK_ONE_OPTION_ENABLE_SEARCH'),
tagText: "",
tagPrefix: this.$i18n.t('ID_SEARCH_BY_PARTICIPATION'),
items:[
{
id: "startedBy",
value: "",
options: [],
placeholder: "",
status: "not_accepted",
title: this.$i18n.t("ID_STARTED_BY")
},
{
id: "completedBy",
value: "",
options: [],
placeholder: "",
disabled: true,
status: "not_accepted",
title: this.$i18n.t("ID_COMPLETED_BY")
}
],
makeTagText: function (params, data) {
let text = data && (data[0].value || data[1].value) ? "": data[0].title;
if(data && data[0].value){
text += data[0].title + ": " + data[0].label;
text += data && data[1].value ? "; ": "";
}
if(data && data[1].value){
text += data[1].title + ": " + data[1].label;
}
return text;
}
},
{
type: "ProcessCategory",
id: "processCategory",
title: `${this.$i18n.t('ID_FILTER')}: ${this.$i18n.t('ID_BY_PROCESS_CATEGORY')}`,
optionLabel: this.$i18n.t('ID_BY_PROCESS_CATEGORY'),
detail: "",
tagText: "",
tagPrefix: this.$i18n.t('ID_SEARCH_BY_PROCESS_CATEGORY'),
items:[
{
id: "category",
value: "",
options: [],
placeholder: ""
}
],
makeTagText: function (params, data) {
return `${params.tagPrefix}: ${data[0].label || ''}`;
}
}
],
selected: "",
itemModel: {},
@@ -492,8 +554,9 @@ export default {
filterVar: value.id,
fieldId: item,
value: '',
label: "",
options: []
label: value.label,
options: [],
title: value.title
});
}
});

View File

@@ -7,21 +7,33 @@
>
<template v-slot:body>
<b-form-group>
<b-form-radio-group
v-model="selected"
:options="filterItems"
value-field="id"
text-field="optionLabel"
name="flavour-2a"
stacked
></b-form-radio-group>
<b-form-radio-group
v-model="selected"
:options="filterItems"
value-field="id"
text-field="optionLabel"
name="flavour-2a"
stacked
></b-form-radio-group>
<b-form-group>
</b-form-group>
<b-form-checkbox
id="checkbox-1"
v-model="byProcessName"
name="checkbox-1"
value="processName"
>
{{$t('ID_BY_PROCESS_NAME') }}
</b-form-checkbox>
</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">
@@ -68,124 +80,169 @@
<script>
import SearchPopover from "./popovers/SearchPopover.vue";
import CaseIntegerNumber from "./popovers/CaseIntegerNumber.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 api from "./../../api/index";
export default {
name: "Cases",
props: ["filters", "title"],
props: ["filters", "title", "icon"],
components: {
SearchPopover,
CaseIntegerNumber,
CaseNumber,
CaseTitle,
ProcessName,
DateFilter,
TaskTitle,
CurrentUser
},
data() {
return {
searchLabel: this.$i18n.t("ID_SEARCH"),
addSearchTitle: this.$i18n.t("ID_ADD_SEARCH_FILTER_CRITERIA"),
searchTags: [],
searchLabel: this.$i18n.t("ID_SEARCH"),
addSearchTitle: this.$i18n.t("ID_ADD_SEARCH_FILTER_CRITERIA"),
searchTags: [],
dataLoaded: false,
filterItems: [
{
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}`;
},
},
{
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}`;
},
},
{
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}`;
}
},
{
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 || ''}`;
}
},
{
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: {
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) {
filterItems: [
{
type: "CaseIntegerNumber",
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: "caseNumber",
value: "",
return `${this.tagPrefix} ${data[0].options && data[0].options.label || ''}`;
}
},
],
autoShow: true,
makeTagText: function (params, data) {
return `${params.tagPrefix}: ${data[0].value}`;
},
},
{
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}`;
},
},
{
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: true,
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) || ""
}`;
},
},
{
type: "TaskTitle",
id: "taskTitle",
title: `${this.$i18n.t("ID_FILTER")}: ${this.$i18n.t(
"ID_TASK_NAME"
)}`,
optionLabel: this.$i18n.t("ID_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 || ""}`;
},
},
],
selected: "",
itemModel: {},
selected: "",
itemModel: {},
byProcessName: ""
};
},
mounted() {
@@ -196,57 +253,97 @@ export default {
o.autoShow = false;
});
this.setFilters(fils);
this.dataLoaded = true;
}
},
watch: {
filters: function (filters) {
this.searchTags = [];
this.selected = "";
this.setFilters(filters);
},
filters: {
immediate: true,
handler(newVal, oldVal) {
this.searchTags = [];
this.selected = [];
//Prevent show popover at the first time
if (newVal.length && this.dataLoaded) {
this.setFilters(newVal, oldVal);
this.searchClickHandler();
}
}
}
},
methods: {
/**
* 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.selected;
});
if (element) {
_.forEach(element.items, function (value, key) {
item = {
filterVar: value.id,
fieldId: self.selected,
value: "",
label: "",
options: [],
};
initialFilters.push(item);
let self = this,
element,
initialFilters = [],
item;
this.$root.$emit("bv::hide::popover");
element = _.find(this.filterItems, function (o) {
return o.id === self.selected;
});
}
this.$emit("onUpdateFilters", { params: initialFilters, refresh: false });
if (element) {
initialFilters = this.prepareFilterItems(element.items, this.selected, true);
}
//adding process name filter
if (self.byProcessName !== "") {
initialFilters =[...new Set([...initialFilters,...this.prepareFilterItems(this.processName.items, self.byProcessName, true)])];
}
this.$emit("onUpdateFilters", {params: initialFilters, refresh: false});
},
/**
* Prepare the filter items
* @param {array} items
* @param {id} string
* @param {boolean} restore
*/
prepareFilterItems(items, id, restore){
let initialFilters = [],
self = this,
filter,
item;
_.forEach(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,
fieldId: id,
value: '',
label: "",
options: []
};
initialFilters.push(item);
}
});
return initialFilters;
},
/**
* Set Filters and make the tag labels
* @param {object} filters json to manage the query
*/
setFilters(filters) {
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.selected = component.id;
self.itemModel[component.id] = component;
self.itemModel[component.id].autoShow = typeof item.autoShow !== "undefined" ? item.autoShow : true
self.searchTags.push(component.id);
self.selected.push(component.id);
self.itemModel[component.id] = component;
self.itemModel[component.id].autoShow = typeof item.autoShow !== "undefined" ? item.autoShow : true;
if (oldVal && !oldVal.length) {
self.updateSearchTag(item);
}
}
if(item.fieldId === "processName") {
self.searchTags.push(self.processName.id);
self.byProcessName = self.processName.id;
self.itemModel[self.processName.id] = self.processName;
self.itemModel[self.processName.id].autoShow = typeof self.processName.autoShow !== "undefined" ? self.processName.autoShow : true;
}
});
},
@@ -293,8 +390,16 @@ export default {
* @param {string} tag filter identifier
*/
customRemove(removeTag, tag) {
this.selected = "";
this.$emit("onUpdateFilters", { params: [], refresh: true });
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
@@ -330,7 +435,12 @@ export default {
}
.v-search-title {
padding-right: 20px;
padding-right: 10px;
line-height: 40px;
}
.pm-in-text-icon {
font-size: 2vw;
padding-right: 10px;
line-height: 3vw;
}
</style>

View File

@@ -16,12 +16,22 @@
stacked
></b-form-radio-group>
</b-form-group>
<b-form-checkbox
id="checkbox-1"
v-model="byProcessName"
name="checkbox-1"
value="processName"
>
{{$t('ID_BY_PROCESS_NAME') }}
</b-form-checkbox>
</template>
</SearchPopover>
<div class="p-1 v-flex">
<h5 class="v-search-title">{{ title }}</h5>
<h5 class="v-search-title">{{ title }}</h5>
<div class="pm-mc-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">
@@ -69,7 +79,7 @@
<script>
import SearchPopover from "./popovers/SearchPopover.vue";
import CaseIntegerNumber from "./popovers/CaseIntegerNumber.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";
@@ -78,10 +88,10 @@ import api from "./../../api/index";
export default {
name: "MyCasesFilter",
props: ["filters","title"],
props: ["filters","title", "icon"],
components:{
SearchPopover,
CaseIntegerNumber,
CaseNumber,
CaseTitle,
ProcessName,
DateFilter,
@@ -92,10 +102,9 @@ export default {
searchLabel: this.$i18n.t('ID_SEARCH'),
addSearchTitle: this.$i18n.t('ID_ADD_SEARCH_FILTER_CRITERIA'),
searchTags: [],
filterItems: [
{
type: "CaseIntegerNumber",
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'),
@@ -104,7 +113,7 @@ export default {
tagPrefix: this.$i18n.t('ID_SEARCH_BY_CASE_NUMBER'),
items:[
{
id: "caseNumber",
id: "filterCases",
value: ""
}
],
@@ -131,29 +140,7 @@ export default {
makeTagText: function (params, data) {
return `${this.tagPrefix} ${data[0].value}`;
}
},
{
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: true,
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 || ''}`;
}
},
},
{
type: "TaskTitle",
id: "taskTitle",
@@ -226,8 +213,31 @@ export default {
}
},
],
processName: {
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 || ''}`;
}
},
selected: "",
itemModel: {}
itemModel: {},
byProcessName: ""
};
},
mounted() {
@@ -241,14 +251,17 @@ export default {
}
},
watch: {
filters: function (filters) {
this.searchTags = [];
this.selected = "";
this.setFilters(filters);
filters: {
immediate: true,
handler(newVal, oldVal) {
this.searchTags = [];
this.selected = [];
this.setFilters(newVal);
}
}
},
methods: {
/**
* Add filter criteria save button handler
*/
@@ -257,23 +270,43 @@ export default {
element,
initialFilters = [],
item;
// element = _.find(this.filterItems, function(o) { return o.id === self.selected; });
this.$root.$emit('bv::hide::popover');
element = _.find(this.filterItems, function(o) { return o.id === self.selected; });
if (element) {
_.forEach(element.items, function(value, key) {
item = {
filterVar: value.id,
fieldId: self.selected,
value: '',
label: "",
options: []
};
initialFilters.push(item);
});
}
if (element) {
initialFilters = this.prepareFilterItems(element.items, this.selected, true);
}
//adding process name filter
initialFilters =[...new Set([...initialFilters,...this.prepareFilterItems(this.processName.items, self.byProcessName, true)])];
this.$emit("onUpdateFilters", {params: initialFilters, refresh: false});
},
/**
* Prepare the filter items
* @param {array} items
* @param {id} string
* @param {boolean} restore
*/
prepareFilterItems(items, id, restore){
let initialFilters = [],
self = this,
filter,
item;
_.forEach(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,
fieldId: id,
value: '',
label: "",
options: []
};
initialFilters.push(item);
}
});
return initialFilters;
},
/**
* Set Filters and make the tag labels
* @param {object} filters json to manage the query
@@ -288,6 +321,12 @@ export default {
self.itemModel[component.id] = component;
self.itemModel[component.id].autoShow = typeof item.autoShow !== "undefined" ? item.autoShow : true;
}
if(item.fieldId === "processName") {
self.searchTags.push(self.processName.id);
self.byProcessName = self.processName.id;
self.itemModel[self.processName.id] = self.processName;
self.itemModel[self.processName.id].autoShow = typeof self.processName.autoShow !== "undefined" ? self.processName.autoShow : true;
}
});
},
dataToFilter(id) {
@@ -327,15 +366,23 @@ export default {
* @param {string} tag filter identifier
*/
customRemove(removeTag, tag) {
this.selected = "";
this.$emit("onUpdateFilters", {params: [], refresh: true});
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) {
updateSearchTag(params) {
let temp = this.filters.concat(params);
temp = [...new Set([...this.filters,...params])]
this.$emit("onUpdateFilters", {params: temp, refresh: true});
@@ -363,8 +410,13 @@ export default {
}
.v-search-title {
padding-right: 20px;
padding-right: 10px;
line-height: 40px;
}
.pm-mc-text-icon{
font-size: 2vw;
padding-right: 10px;
line-height: 3vw;
}
</style>

View File

@@ -0,0 +1,151 @@
<template>
<div>
<SearchPopover :target="tag" @savePopover="onOk" :title="info.title">
<template v-slot:body>
<p>{{ info.detail }}</p>
<form ref="form" @submit.stop.prevent="handleSubmit">
<b-form-group
label-for="name"
:invalid-feedback="$t('ID_PROCESS_IS_REQUIRED')"
>
<b-form-checkbox
id="started"
v-model="filter[0].status"
name="started"
value="accepted"
unchecked-value="not_accepted"
>
{{$t("ID_STARTED_BY")}}
</b-form-checkbox>
<multiselect
v-model="filter[0].options"
:options="users"
:placeholder="$t('ID_USER_NAME')"
label="USR_FULLNAME"
track-by="USR_ID"
:show-no-results="false"
@search-change="asyncFind"
:loading="isLoading"
id="started"
:limit="10"
:clear-on-select="true"
:disabled="filter[0].status !== 'accepted'"
>
</multiselect>
</b-form-group>
<b-form-group>
<b-form-checkbox
id="completed"
v-model="filter[1].status"
name="completed"
value="accepted"
unchecked-value="not_accepted"
>
{{$t("ID_COMPLETED_BY")}}
</b-form-checkbox>
<multiselect
v-model="filter[1].options"
:options="users"
:placeholder="$t('ID_USER_NAME')"
label="USR_FULLNAME"
track-by="USR_ID"
:show-no-results="false"
@search-change="asyncFind"
:loading="isLoading"
id="completed"
:limit="10"
:clear-on-select="true"
:disabled="filter[1].status !== 'accepted'"
>
</multiselect>
</b-form-group>
</form>
</template>
</SearchPopover>
</div>
</template>
<script>
import SearchPopover from "./SearchPopover.vue";
import Multiselect from "vue-multiselect";
import api from "./../../../api/index";
export default {
components: {
SearchPopover,
Multiselect
},
props: ["tag", "info", "filter"],
data() {
return {
users: [],
isLoading: false,
started: "",
completed: ""
};
},
watch: {
filter: {
immediate: true,
handler(newVal, oldVal) {
if (newVal[0].status === "not_accepted") {
newVal[0].options = [];
newVal[0].label = "";
newVal[0].value = "";
}
if (newVal[1].status === "not_accepted") {
newVal[1].options = [];
newVal[1].label = "";
newVal[1].value = "";
}
}
}
},
methods: {
/**
* Find asynchronously in the server
* @param {string} query - string from the text field
*/
asyncFind(query) {
this.isLoading = true;
api.filters
.userList(query)
.then((response) => {
this.users = response.data;
this.isLoading = false;
})
.catch((e) => {
console.error(err);
});
},
/**
* Form validations review
*/
checkFormValidity() {
const valid = this.query !== "";
this.valueState = valid;
return valid;
},
/**
* On Ok event handler
*/
onOk() {
this.handleSubmit();
},
/**
* Form submit handler
*/
handleSubmit() {
this.filter[0].value = this.filter[0].options.USR_ID;
this.filter[0].label = this.filter[0].options.USR_FULLNAME;
this.filter[1].value = this.filter[1].options.USR_ID;
this.filter[1].label = this.filter[1].options.USR_FULLNAME;
this.$emit("updateSearchTag", this.filter);
this.$root.$emit("bv::hide::popover");
}
}
};
</script>
<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>
<style scoped></style>

View File

@@ -0,0 +1,97 @@
<template>
<div>
<SearchPopover :target="tag" @savePopover="onOk" :title="info.title">
<template v-slot:body>
<p>{{ info.detail }}</p>
<form ref="form" @submit.stop.prevent="handleSubmit">
<b-form-group
label-for="name"
:invalid-feedback="$t('ID_PROCESS_IS_REQUIRED')"
>
<multiselect
v-model="filter[0].options"
:options="categories"
:placeholder="$t('ID_CATEGORY_NAME')"
label="CATEGORY_NAME"
track-by="CATEGORY_ID"
:show-no-results="false"
@search-change="asyncFind"
:loading="isLoading"
id="started"
:limit="10"
:clear-on-select="true"
>
</multiselect>
</b-form-group>
</form>
</template>
</SearchPopover>
</div>
</template>
updateSearchTag
<script>
import SearchPopover from "./SearchPopover.vue";
import Multiselect from "vue-multiselect";
import api from "./../../../api/index";
export default {
components: {
SearchPopover,
Multiselect
},
props: ["tag", "info", "filter"],
data() {
return {
categories: [],
isLoading: false,
started: "",
completed: ""
};
},
methods: {
/**
* Find asynchronously in the server
* @param {string} query - string from the text field
*/
asyncFind(query) {
this.isLoading = true;
api.filters
.categories(query)
.then((response) => {
this.categories = response.data;
this.isLoading = false;
})
.catch((e) => {
console.error(err);
});
},
/**
* Form validations review
*/
checkFormValidity() {
const valid = this.query !== "";
this.valueState = valid;
return valid;
},
/**
* On Ok event handler
*/
onOk() {
this.handleSubmit();
},
/**
* Form submit handler
*/
handleSubmit() {
this.filter[0].value = this.filter[0].options.CATEGORY_ID;
this.filter[0].label = this.filter[0].options.CATEGORY_NAME;
this.$emit("updateSearchTag", this.filter);
this.$root.$emit("bv::hide::popover");
}
}
};
</script>
<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>
<style scoped></style>

View File

@@ -0,0 +1,92 @@
<template>
<nav aria-label="breadcrumb">
<ol class="vp-breadcrumb">
<li
v-for="item in formatOptions(options)"
:key="item.label"
:class="item.classObject"
>
<span v-if="item.classObject.active === true">{{ item.label }}</span>
<a
v-if="item.classObject.active === false"
href="#"
@click="item.onClick"
>{{ item.label }}</a
>
</li>
<div
v-for="item in settings"
:key="item.id"
class="vp-bread-crumbs-settings vp-float-right vp-inline-block"
>
<span
@click="item.onClick"
data-bs-toggle="tooltip"
data-bs-placement="top"
:title="item.tooltip || ''"
>
<i :class="formatClass(item)"></i>
</span>
</div>
</ol>
</nav>
</template>
<script>
import _ from "lodash";
export default {
name: "BreadCrumb",
props: ["options", "settings"],
data() {
return {};
},
methods: {
/**
* format options to Bread Crumbs
*/
formatOptions(data) {
let options = data;
for (let i = 0; i <= options.length - 1; i++) {
if (i === options.length - 1) {
options[i].classObject = {
"breadcrumb-item": true,
active: true,
"vp-inline-block": true,
};
} else {
options[i].classObject = {
"breadcrumb-item": true,
active: false,
"vp-inline-block": true,
};
}
}
return options;
},
formatClass(item) {
return item.class;
},
},
};
</script>
<style scoped>
.vp-float-right {
float: right;
}
.vp-bread-crumbs-settings {
line-height: 20px;
}
.vp-breadcrumb {
padding: 0.75rem 1rem;
margin-bottom: 1rem;
list-style: none;
background-color: #e9ecef;
border-radius: 0.25rem;
}
.vp-inline-block {
display: inline-block;
}
</style>

View File

@@ -0,0 +1,83 @@
<template>
<span
:id="`label-${data.id}`"
@mouseover="hoverHandler"
v-b-tooltip.hover
@mouseleave="unhoverHandler"
v-bind:class="{highlightText: isHighlight}"
>
{{ data.title }}
<b-tooltip
:target="`label-${data.id}`"
triggers="hoverHandler"
:ref="`tooltip-${data.id}`"
>
{{ labelTooltip }}
</b-tooltip>
</span>
</template>
<script>
import api from "./../../api/index";
export default {
name: "CustomTooltip",
props: {
data: Object
},
data() {
return {
labelTooltip: "",
hovering: "",
show: false,
menuMap: {
CASES_INBOX: "inbox",
CASES_DRAFT: "draft",
CASES_PAUSED: "paused",
CASES_SELFSERVICE: "unassigned"
},
isHighlight: false
};
},
methods: {
/**
* Delay the hover event
*/
hoverHandler() {
this.hovering = setTimeout(() => { this.setTooltip() }, 3000);
},
/**
* Reset the delay and hide the tooltip
*/
unhoverHandler() {
let key = `tooltip-${this.data.id}`;
this.labelTooltip = "";
this.$refs[key].$emit("close");
clearTimeout(this.hovering);
},
/**
* Set the label to show in the tooltip
*/
setTooltip() {
let that = this;
api.menu.getTooltip(that.data.page).then((response) => {
let key = `tooltip-${that.data.id}`;
that.labelTooltip = response.data.label;
that.$refs[key].$emit("open");
that.isHighlight = false;
});
},
/**
* Set bold the label
*/
setHighlight() {
this.isHighlight = true;
}
},
};
</script>
<style>
.highlightText {
font-weight: 900;
}
</style>

View File

@@ -0,0 +1,144 @@
<template>
<div class="float-right">
<transition name="fade">
<div
class="v-inline"
v-show="showActions"
ref="ellipsis"
>
<div class="buttonGroup">
<b-button
v-for="item in data.buttons"
:key="item.name"
variant="outline-info"
@click="executeFunction(item.fn)"
>
<i class="custom-icon" :class="item.icon" v-bind:style="{color: item.color}"></i>
</b-button>
</div>
</div>
</transition>
<div class="ellipsis-button">
<div @click="showActionButtons()">
<i class="fas fa-ellipsis-v"></i>
</div>
</div>
</div>
</template>
<script>
import eventBus from '../../home/EventBus/eventBus';
export default {
name: "Ellipsis",
props: {
data: Object
},
data () {
return {
showActions: false
}
},
mounted(){
let that = this;
eventBus.$on('ellipsis::hide', (data) => {
that.hideActionButtons();
});
},
methods: {
/**
* Callback function from parent
*/
executeFunction(fn) {
if (fn) {
fn();
}
},
/**
* Show the action buttons by row
*/
showActionButtons() {
var i,
showOld = this.showActions,
elelemts;
eventBus.$emit("ellipsis::hide",{});
this.showActions = !showOld;
if (this.showActions) {
if (this.$parent.Row !== undefined) {
for (i = 0; i < this.$parent.$parent.$parent.$children.length -1 ; i++){
this.$parent.$parent.$parent.$children[i].$el.style.opacity = 0.15
}
} else if (this.$parent.item !== undefined) {
if (this.$parent.$parent.$parent.$refs.vueListView !== undefined) {
elelemts = this.$parent.$el.getElementsByClassName('col-sm-5');
elelemts[0].style.opacity = 0.4;
elelemts[1].style.opacity = 0.4;
}
if (this.$parent.$parent.$parent.$refs.vueCardView !== undefined) {
this.$parent.$el.getElementsByClassName('col-sm-9')[0].style.opacity = 0.2
}
}
} else {
this.hideActionButtons();
}
},
/**
* Hide action buttons
*/
hideActionButtons() {
var i,
elelemts;
this.showActions = false;
if (this.$parent.Row !== undefined) {
for (i = 0; i < this.$parent.$parent.$parent.$children.length -1 ; i++){
this.$parent.$parent.$parent.$children[i].$el.style.opacity = 1
}
} else if (this.$parent.item !== undefined) {
if (this.$parent.$parent.$parent.$refs.vueListView !== undefined) {
elelemts = this.$parent.$el.getElementsByClassName('col-sm-5');
elelemts[0].style.opacity = 1;
elelemts[1].style.opacity = 1;
}
if (this.$parent.$parent.$parent.$refs.vueCardView !== undefined) {
this.$parent.$el.getElementsByClassName('col-sm-9')[0].style.opacity = 1;
}
}
},
}
}
</script>
<style>
.v-btn-request {
display: inline-block;
}
.v-inline {
display: inline-block;
}
.ellipsis-button {
font-size: 22px;
width: 15px;
text-align: center;
float: inherit;
margin-top: 9px;
}
.buttonGroup {
position: relative;
flex-direction: row-reverse;
width: 0px;
z-index: 999;
display: inline-flex !important;
opacity: 1 !important;
}
.btn-outline-info {
border: none;
font-size: 25px;
}
.fade-enter-active, .fade-leave-active {
transition: opacity 0.5s;
position: relative;
}
.fade-enter, .fade-leave-to {
opacity: 0;
position: relative;
}
</style>

View File

@@ -69,7 +69,7 @@ export default {
.ellipsis {
white-space: nowrap;
width: 140px;
width: auto;
overflow: hidden;
text-overflow: ellipsis;
}

View File

@@ -0,0 +1,71 @@
<template>
<div class="grouped-cell">
<div class="d-flex justify-content-center avatar" id="user">
<b-avatar
variant="info"
:src="data.userAvatar"
size="2em"
></b-avatar>
</div>
<b-popover
target="user"
placement="top"
ref="popover"
triggers="hover"
>
<b-row >
<b-col md="3">
<b-avatar
variant="info"
:src="data.userAvatar"
size="4em"
></b-avatar>
</b-col>
<b-col md="9">
<div class="font-weight-bold">{{data.userInfo}}</div>
<div v-if="data.userPosition !== ''">{{data.userPosition}}</div>
<b-link :href="mailto(data.userEmail)" >{{data.userEmail}}</b-link>
</b-col>
</b-row>
</b-popover>
</div>
</template>
<script>
export default {
name: "OwnerCell",
props: ["data"],
data() {
return {
//Color map for ["In Progress", "overdue", "inDraft", "paused", "unnasigned"]
colorMap: ["green", "red", "orange", "aqua", "silver"],
id: "avatar-" + _.random(1000000),
statusId: "status-" + _.random(1000000)
};
},
methods: {
/**
* Mail to link
* @param {string} email
* @returns {string}
*/
mailto: function(email) {
return "mailto:" + email;
}
}
};
</script>
<style>
.popover {
max-width: 600px !important;
min-width: 200px !important;
}
.grouped-cell {
font-size: small;
}
.avatar {
color: "red";
width: "1.3em";
}
</style>

View File

@@ -0,0 +1,170 @@
<template>
<div class="pm-all-view-popover">
<b-popover
:target="target"
ref="popover"
triggers="click"
placement="bottom"
@show="onshow"
>
<template #title>{{ $t("ID_COLUMNS").toUpperCase() }}</template>
<div>
<div class="input-group input-group-sm mb-3">
<span class="input-group-text" id="inputGroup-sizing-sm"
><i class="fas fa-search"></i
></span>
<input
type="text"
class="form-control"
aria-describedby="inputGroup-sizing-sm"
@keyup="search"
v-model="text"
/>
</div>
<div class="form-check border-bottom">
<input
class="form-check-input"
type="checkbox"
v-model="allColumns"
@change="toogleAllColumns"
/>
<label class="form-check-label" for="flexCheckDefault">
{{ $t("ID_ALL") }}
</label>
</div>
<b-form-group>
<b-form-checkbox-group
v-model="localSelected"
:options="options"
value-field="key"
text-field="value"
name="flavour-2a"
@change="changeOptions"
stacked
></b-form-checkbox-group>
</b-form-group>
<div class="v-popover-footer">
<div class="float-right">
<b-button @click="onClose" size="sm" variant="danger">
{{ $t("ID_CANCEL") }}</b-button
>
<b-button @click="onSave" size="sm" variant="success">{{
$t("ID_SAVE")
}}</b-button>
</div>
</div>
</div>
</b-popover>
</div>
</template>
<script>
export default {
props: ["target", "options", "selected"],
data() {
return {
localSelected: [],
text: "",
results: [],
allColumns: false,
};
},
mounted() {
this.results = this.options;
this.localSelected = this.selected || [];
},
watch: {
selected: function (newSelection, oldSelection) {
this.localSelected = newSelection;
}
},
methods: {
/**
* Close buton click handler
*/
onClose() {
this.$refs.popover.$emit("close");
this.$emit("closePopover");
},
/**
* Save button click handler
*/
onSave() {
let sels;
sels = _.clone(this.localSelected);
this.$emit("onUpdateColumnSettings", sels);
},
/**
* Show popover event handler
*/
onshow() {
this.$root.$emit("bv::hide::popover");
},
/**
* Search in the column name
*/
search() {
let txt = this.text.toLowerCase(),
val,
opts = [];
opts = _.filter(this.options, function (o) {
val = o.value.toLowerCase();
return val.search(txt) != -1;
});
this.results = opts;
},
/**
* Toogle all options in popover
*/
toogleAllColumns() {
let res = [];
if (this.allColumns) {
_.each(this.options, function (o) {
res.push(o.key);
});
}
this.localSelected = res;
},
/**
* Handler when change options event
*/
changeOptions() {
let that = this,
res = [];
_.each(this.options, function (o) {
if (
_.findIndex(that.localSelected, function (v) {
return v === o.key;
}) != -1
) {
res.push(o.key);
}
});
this.localSelected = res;
},
},
};
</script>
<style scoped>
.pm-all-view-popover .popover {
max-width: 350px !important;
min-width: 200px !important;
}
.v-popover-footer {
display: flow-root;
}
</style>

View File

@@ -0,0 +1,20 @@
<template>
<div class="title-cell">
<div
v-for="item in data"
:key="item.del_id"
class="d-flex mb-3"
>
<p>
{{ item.thread_title }}
</p>
</div>
</div>
</template>
<script>
export default {
name: "ThreadTitleCell",
props: ["data"]
}
</script>

View File

@@ -0,0 +1,29 @@
<template>
<span v-if="settings()" :class="classObject" :id="id"> </span>
</template>
<script>
export default {
name: "VtSettingsControl",
props: ["props", "parent"],
mounted() {},
methods: {
settings() {
return (
this.props.opts.settings && this.props.opts.settings[this.parent.column]
);
},
},
computed: {
classObject() {
return this.settings()
? this.props.opts.settings[this.parent.column]["class"]
: this.props.class;
},
id() {
return this.settings()
? this.props.opts.settings[this.parent.column]["id"]
: "default-settings-case";
},
},
};
</script>

View File

@@ -0,0 +1,19 @@
<template>
<i v-if="props.sortable" :class="icon"></i>
</template>
<script>
export default {
name: "VtSortControl",
props: ["props"],
computed: {
icon() {
// if not sorted return base icon
if (!this.props.sortStatus.sorted) return "fas fa-sort";
// return sort direction icon
return this.props.sortStatus.asc
? "fas fa-sort-amount-up"
: "fas fa-sort-amount-down";
},
},
};
</script>

View File

@@ -0,0 +1,42 @@
<template>
<th slot-scope="props" v-on="events()" v-bind="props.thAttrs" :key="random">
<span class="VueTables__heading" :title="props.title">
<vnodes :vnodes="props.heading" />
</span>
<vt-sort-control />
<vt-settings-control :props="props" :parent="$parent" />
</th>
</template>
<script>
import VtSortControl from "vue-tables-2/compiled/components/VtSortControl";
import VtSettingsControl from "./VtSettingsControl.vue";
export default {
name: "VtTableHeading",
components: {
VtSortControl,
VtSettingsControl,
vnodes: {
functional: true,
render: (h, ctx) =>
typeof ctx.props.vnodes === "object"
? ctx.props.vnodes
: [ctx.props.vnodes],
},
},
computed: {
random() {
return _.random(0, 10000000000);
},
},
props: ["props"],
mounted() {},
methods: {
events() {
return this.props.opts.settings &&
this.props.opts.settings[this.$parent.column]
? this.props.opts.settings[this.$parent.column]["events"]
: this.props.thEvents;
},
},
};
</script>

View File

@@ -24,13 +24,14 @@
/>
<modal-new-request ref="newRequest"></modal-new-request>
<settings-popover :options="formatColumnSettings(options.headings)" target="pm-dr-column-settings" @onUpdateColumnSettings="onUpdateColumnSettings" :key="random+1" :selected="formatColumnSelected(columns)"/>
<v-server-table
:data="tableData"
:columns="columns"
:options="options"
ref="vueTable"
@row-click="onRowClick"
:key="random"
>
<div slot="info" slot-scope="props">
<b-icon
@@ -42,8 +43,8 @@
<div slot="case_number" slot-scope="props">
{{ props.row.CASE_NUMBER }}
</div>
<div slot="case_title" slot-scope="props">
{{ props.row.CASE_TITLE }}
<div slot="thread_title" slot-scope="props">
<ThreadTitleCell :data="props.row.THREAD_TITLE" />
</div>
<div slot="case_status" slot-scope="props">
{{ props.row.APP_STATUS }}
@@ -82,27 +83,32 @@
</div>
</template>
<script>
import ButtonFleft from "../components/home/ButtonFleft.vue";
import ModalNewRequest from "./ModalNewRequest.vue";
import AdvancedFilter from "../components/search/AdvancedFilter";
import TaskCell from "../components/vuetable/TaskCell.vue";
import CurrentUserCell from "../components/vuetable/CurrentUserCell.vue";
import ModalComments from "./modal/ModalComments.vue";
import api from "./../api/index";
import utils from "./../utils/utils";
import ButtonFleft from "../../components/home/ButtonFleft.vue";
import ModalNewRequest from "../ModalNewRequest.vue";
import AdvancedFilter from "../../components/search/AdvancedFilter";
import TaskCell from "../../components/vuetable/TaskCell.vue";
import CurrentUserCell from "../../components/vuetable/CurrentUserCell.vue";
import ModalComments from "../modal/ModalComments.vue";
import ThreadTitleCell from "../../components/vuetable/ThreadTitleCell.vue"
import api from "../../api/index";
import utils from "../../utils/utils";
import defaultMixin from "./defaultMixins.js";
export default {
name: "AdvancedSearch",
mixins: [defaultMixin],
components: {
AdvancedFilter,
ButtonFleft,
ModalNewRequest,
TaskCell,
CurrentUserCell,
ModalComments
ModalComments,
ThreadTitleCell,
},
props: ["id", "name", "filters"],
data() {
let that = this;
return {
dismissSecs: 5,
dismissCountDown: 0,
@@ -123,9 +129,9 @@ export default {
},
columns: [
"case_number",
"case_title",
"status",
"process_name",
"status",
"thread_title",
"task",
"current_user",
"start_date",
@@ -137,11 +143,10 @@ export default {
options: {
filterable: false,
headings: {
info: "",
case_number: this.$i18n.t("ID_MYCASE_NUMBER"),
case_title: this.$i18n.t("ID_CASE_TITLE"),
status: this.$i18n.t("ID_STATUS"),
process_name: this.$i18n.t("ID_PROCESS_NAME"),
status: this.$i18n.t("ID_STATUS"),
thread_title: this.$i18n.t('ID_CASE_THREAD_TITLE'),
task: this.$i18n.t("ID_TASK"),
current_user: this.$i18n.t("ID_CURRENT_USER"),
start_date: this.$i18n.t("ID_START_DATE"),
@@ -166,10 +171,12 @@ export default {
selectAllMode: "page",
programmatic: false,
},
sortable: [],
orderBy: {},
requestFunction(data) {
return this.$parent.$parent.getCasesForVueTable(data);
},
customFilters: ["myfilter"],
customFilters: ["myfilter"]
},
pmDateFormat: window.config.FORMATS.dateFormat,
clickCount: 0,
@@ -216,12 +223,17 @@ export default {
limit = data.limit,
filters = {},
start = data.page === 1 ? 0 : limit * (data.page - 1);
paged = start + "," + limit;
filters["paged"] = paged;
return new Promise((resolutionFunc, rejectionFunc) => {
_.forIn(this.filters, function(item, key) {
paged = start + "," + limit ;
filters = {
limit: limit,
offset: start
};
_.forIn(this.filters, function (item, key) {
if(filters && item.value) {
filters[item.filterVar] = item.value;
});
}
});
return new Promise((resolutionFunc, rejectionFunc) => {
api.cases
.search(filters)
.then((response) => {
@@ -247,7 +259,7 @@ export default {
_.forEach(response, (v) => {
data.push({
CASE_NUMBER: v.APP_NUMBER,
CASE_TITLE: v.DEL_TITLE,
THREAD_TITLE: v.THREAD_TITLES,
PROCESS_NAME: v.PRO_TITLE,
TASK: this.formatTasks(v.THREAD_TASKS),
USER_DATA: this.formatUser(v.THREAD_USERS),

View File

@@ -0,0 +1,46 @@
import api from "../../api/index";
export default {
data() {
return {
random: 1
};
},
methods: {
/**
* Format columns for custom columns
* @param {*} headings
* @returns
*/
formatColumnSettings(headings) {
let res = [];
_.forEach(headings, function (value, key) {
if (key != "actions") {
res.push({ value, key });
}
});
return res;
},
/**
* Formating the columns selected
* @param {*} columns
* @returns
*/
formatColumnSelected(columns) {
let cols = _.clone(columns);
cols.pop();
return cols;
},
/**
* Event handler when update the settings columns
* @param {*} columns
*/
onUpdateColumnSettings(columns) {
let cols = columns;
if (_.findIndex(cols, 'actions') == -1) {
cols.push("actions");
}
this.columns = cols;
this.random = _.random(0, 10000000000);
}
}
}

View File

@@ -32,11 +32,11 @@
<div slot="task" slot-scope="props">
<TaskCell :data="props.row.TASK" />
</div>
<div slot="case_title" slot-scope="props">
{{ props.row.CASE_TITLE }}
<div slot="thread_title" slot-scope="props">
{{ props.row.THREAD_TITLE }}
</div>
<div slot="assignee" slot-scope="props">
{{ props.row.ASSIGNEE }}
<div slot="current_user" slot-scope="props">
<CurrentUserCell :data="props.row.USER_DATA" />
</div>
<div slot="status" slot-scope="props">
{{ props.row.STATUS }}
@@ -48,9 +48,15 @@
<b-button
v-if="props.row.STATUS === 'OPEN'"
@click="onClick(props)"
variant="outline-primary"
variant="outline-success"
>{{ $t("ID_CONTINUE") }}</b-button
>
<b-button
v-if="props.row.STATUS === 'PAUSED'"
@click="onClickUnpause(props)"
variant="outline-primary"
>{{ $t("ID_UNPAUSE") }}</b-button
>
</div>
</v-server-table>
</div>
@@ -114,6 +120,7 @@ import ModalCancelCase from "../home/modal/ModalCancelCase.vue";
import ModalNewRequest from "./ModalNewRequest.vue";
import ModalClaimCase from "./modal/ModalClaimCase.vue";
import TaskCell from "../components/vuetable/TaskCell.vue";
import CurrentUserCell from "../components/vuetable/CurrentUserCell.vue"
import utils from "./../utils/utils";
import Api from "../api/index";
@@ -131,7 +138,8 @@ export default {
ButtonFleft,
ModalNewRequest,
ModalClaimCase,
TaskCell
TaskCell,
CurrentUserCell
},
props: {},
data() {
@@ -152,8 +160,8 @@ export default {
},
columns: [
"task",
"case_title",
"assignee",
"thread_title",
"current_user",
"status",
"due_date",
"actions"
@@ -163,8 +171,8 @@ export default {
options: {
headings: {
task: this.$i18n.t("ID_TASK"),
case_title: this.$i18n.t("ID_CASE_TITLE"),
assignee: this.$i18n.t("ID_CURRENT_USER"),
thread_title: this.$i18n.t('ID_CASE_THREAD_TITLE'),
current_user: this.$i18n.t("ID_CURRENT_USER"),
status: this.$i18n.t("ID_STATUS"),
due_date: this.$i18n.t("ID_DUE_DATE"),
actions: this.$i18n.t("ID_ACTIONS")
@@ -187,6 +195,7 @@ export default {
programmatic: false,
},
filterable: false,
sortable: [],
requestFunction() {
return this.$parent.$parent.getCasesForVueTable();
},
@@ -426,6 +435,9 @@ export default {
that.dataComments.noPerms = response.data.noPerms || 0;
})
.catch((err) => {
if (err.response.data) {
that.showAlert(err.response.data.error.message, "danger");
}
throw new Error(err);
});
},
@@ -499,16 +511,8 @@ export default {
COLOR: v.TAS_COLOR_LABEL
},
],
CASE_TITLE: v.DEL_TITLE,
ASSIGNEE:
v.USR_ID !== 0
? utils.userNameDisplayFormat({
userName: v.USR_USERNAME,
firstName: v.USR_LASTNAME,
lastName: v.USR_LASTNAME,
format: window.config.FORMATS.format || null
})
: this.$i18n.t("ID_UNASSIGNED"),
THREAD_TITLE: v.DEL_TITLE,
USER_DATA: this.formatUser(v.user_tooltip),
STATUS: v.DEL_THREAD_STATUS,
DUE_DATE: v.DEL_TASK_DUE_DATE,
TASK_COLOR: v.TAS_COLOR_LABEL,
@@ -520,6 +524,31 @@ export default {
});
return data;
},
/**
* Format user information to show
*/
formatUser(data) {
var dataFormat = [],
userDataFormat;
userDataFormat = data.usr_id ?
utils.userNameDisplayFormat({
userName: data.usr_firstname,
firstName: data.usr_lastname,
lastName: data.usr_username,
format: window.config.FORMATS.format || null
})
: this.$i18n.t("ID_UNASSIGNED");
dataFormat.push({
USERNAME_DISPLAY_FORMAT: userDataFormat !== "" ? userDataFormat : this.$i18n.t("ID_UNASSIGNED"),
EMAIL: data.usr_email,
POSITION: data.usr_position,
AVATAR: userDataFormat !== this.$i18n.t("ID_UNASSIGNED") ? window.config.SYS_SERVER_AJAX +
window.config.SYS_URI +
`users/users_ViewPhotoGrid?pUID=${data.usr_id}` : "",
UNASSIGNED: userDataFormat !== this.$i18n.t("ID_UNASSIGNED") ? true : false
});
return dataFormat;
},
/**
* Show the alert message
* @param {string} message - message to be displayen in the body
@@ -557,6 +586,18 @@ export default {
this.$emit("onUpdatePage", "XCase");
}
},
/**
* Unpause click handler
*
* @param {object} data
*/
onClickUnpause(data) {
Api.cases.unpause(data.row).then((response) => {
if (response.statusText === "OK") {
this.$refs["vueTable"].getData();
}
});
},
/**
* Claim case
*

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,199 @@
import _ from "lodash";
import api from "../../api/index";
export default {
data() {
let that = this;
return {
typeView: "GRID",
random: 1,
dataCasesList: [],
defaultColumns: [
"case_number",
"case_title",
"process_name",
"task",
"send_by",
"due_date",
"delegation_date",
"priority",
],
dataMultiviewHeader: {
actions: [
{
id: "view-grid",
title: "Grid",
onClick(action) {
that.typeView = "GRID";
},
icon: "fas fa-table",
},
{
id: "view-list",
title: "List",
onClick(action) {
that.typeView = "LIST";
},
icon: "fas fa-list",
},
{
id: "view-card",
title: "Card",
onClick(action) {
that.typeView = "CARD";
},
icon: "fas fa-th",
},
],
},
optionsVueView: {
limit: 10,
dblClick: (event, item, options) => {
this.openCase(item);
},
headings: {
case_number: this.$i18n.t("ID_MYCASE_NUMBER"),
case_title: this.$i18n.t("ID_CASE_TITLE"),
process_name: this.$i18n.t("ID_PROCESS_NAME"),
task: this.$i18n.t("ID_TASK"),
send_by: this.$i18n.t("ID_SEND_BY"),
current_user: this.$i18n.t("ID_CURRENT_USER"),
due_date: this.$i18n.t("ID_DUE_DATE"),
delegation_date: this.$i18n.t("ID_DELEGATION_DATE"),
priority: this.$i18n.t("ID_PRIORITY")
},
columns: [],
requestFunction(data) {
return that.getCases(data);
},
requestFunctionViewMore(data) {
return that.getCasesViewMore(data);
}
}
}
},
created: function () {
},
methods: {
/**
* Get cases for Vue Card View
*/
getCases(data) {
let that = this,
dt,
typeList = that.data.pageParent == "inbox"? "todo": that.data.pageParent,
start = 0,
limit = data.limit,
filters = {};
filters = {
paged: "0," + limit,
};
_.forIn(this.filters, function (item, key) {
filters[item.filterVar] = item.value;
});
return new Promise((resolutionFunc, rejectionFunc) => {
api.cases[typeList](filters)
.then((response) => {
dt = that.formatDataResponse(response.data.data);
resolutionFunc({
data: dt,
count: response.data.total,
});
})
.catch((e) => {
rejectionFunc(e);
});
});
},
/**
* Get cases for Vue Card View
*/
getCasesViewMore(data) {
let that = this,
dt,
paged,
typeList = that.data.pageParent == "inbox"? "todo": that.data.pageParent,
limit = data.limit,
start = data.page === 1 ? 0 : limit * (data.page - 1),
filters = {};
paged = start + "," + limit;
filters = {
paged: paged,
};
_.forIn(this.filters, function (item, key) {
if (filters && item.value) {
filters[item.filterVar] = item.value;
}
});
return new Promise((resolutionFunc, rejectionFunc) => {
api.cases[typeList]
(filters)
.then((response) => {
dt = that.formatDataResponse(response.data.data);
resolutionFunc({
data: dt,
count: response.data.total,
});
})
.catch((e) => {
rejectionFunc(e);
});
});
},
/**
* Event handler when update the settings columns
* @param {*} columns
*/
onUpdateColumnSettings(columns) {
this.columns = this.getTableColumns(columns);
this.random = _.random(0, 10000000000);
},
/**
* Get columns for origin , settings or custom cases list
*/
getColumnsFromSource() {
let dt = _.clone(this.dataCasesList),
res = _.clone(this.defaultColumns);
if (!this.data.customListId) {
res = _.map(_.filter(dt, o => o.set), s => s.field);
}
return res;
},
/**
* Return the columns for table - concat with field "detail" "actions"
*/
getTableColumns(columns) {
return _.concat(["detail"], columns, ["actions"]);
},
/**
* Return options for Table
* @returns Object
*/
getTableOptions() {
let dt = _.clone(this.options);
dt.headings = _.pick(this.headings, this.columns);
return dt;
},
/**
* Return options for Table
* @returns Object
*/
getVueViewOptions() {
let dt = _.clone(this.optionsVueView);
dt.columns = this.cardColumns;
return dt;
},
/**
* Format column settings for popover
* @param {*} headings
* @returns
*/
formatColumnSettings(columns) {
return _.map(_.pick(this.headings, columns), (value, key) => {
return { value, key }
});
}
}
}

View File

@@ -1,337 +0,0 @@
<template>
<div id="v-draft" ref="v-draft" class="v-container-draft">
<button-fleft :data="newCase"></button-fleft>
<modal-new-request ref="newRequest"></modal-new-request>
<CasesFilter
:filters="filters"
:title="$t('ID_DRAFT')"
@onRemoveFilter="onRemoveFilter"
@onUpdateFilters="onUpdateFilters"
/>
<v-server-table
:data="tableData"
:columns="columns"
:options="options"
ref="vueTable"
@row-click="onRowClick"
>
<div slot="detail" slot-scope="props">
<div class="btn-default" @click="openCaseDetail(props.row)">
<i class="fas fa-info-circle"></i>
</div>
</div>
<div slot="case_number" slot-scope="props">
{{ props.row.CASE_NUMBER }}
</div>
<div slot="case_title" slot-scope="props">
{{ props.row.CASE_TITLE }}
</div>
<div slot="process_name" slot-scope="props">
{{ props.row.PROCESS_NAME }}
</div>
<div slot="task" slot-scope="props">
<TaskCell :data="props.row.TASK" />
</div>
<div slot="priority" slot-scope="props">{{ props.row.PRIORITY }}</div>
<div slot="actions" slot-scope="props">
<button class="btn btn-success btn-sm" @click="openCase(props.row)">
{{ $t("ID_OPEN_CASE") }}
</button>
</div>
</v-server-table>
</div>
</template>
<script>
import HeaderCounter from "../components/home/HeaderCounter.vue";
import ButtonFleft from "../components/home/ButtonFleft.vue";
import ModalNewRequest from "./ModalNewRequest.vue";
import CasesFilter from "../components/search/CasesFilter";
import TaskCell from "../components/vuetable/TaskCell.vue";
import api from "./../api/index";
import utils from "./../utils/utils";
export default {
name: "Draft",
components: {
HeaderCounter,
ButtonFleft,
ModalNewRequest,
TaskCell,
CasesFilter,
},
props: ["defaultOption", "filters"],
data() {
return {
newCase: {
title: this.$i18n.t("ID_NEW_CASE"),
class: "btn-success",
onClick: () => {
this.$refs["newRequest"].show();
},
},
columns: [
"detail",
"case_number",
"case_title",
"process_name",
"task",
"priority",
"actions"
],
tableData: [],
options: {
filterable: false,
headings: {
detail: "",
case_number: this.$i18n.t("ID_MYCASE_NUMBER"),
case_title: this.$i18n.t("ID_CASE_TITLE"),
process_name: this.$i18n.t("ID_PROCESS_NAME"),
task: this.$i18n.t("ID_TASK"),
actions: ""
},
selectable: {
mode: "single",
only: function (row) {
return true;
},
selectAllMode: "page",
programmatic: false,
},
requestFunction(data) {
return this.$parent.$parent.getCasesForVueTable(data);
},
texts: {
count:this.$i18n.t("ID_SHOWING_FROM_RECORDS_COUNT"),
first: this.$i18n.t("ID_FIRST"),
last: this.$i18n.t("ID_LAST"),
filter: this.$i18n.t("ID_FILTER") + ":",
limit: this.$i18n.t("ID_RECORDS") + ":",
page: this.$i18n.t("ID_PAGE") + ":",
noResults: this.$i18n.t("ID_NO_MATCHING_RECORDS")
}
},
pmDateFormat: "Y-m-d H:i:s",
clickCount: 0,
singleClickTimer: null,
statusTitle: {
"ON_TIME": this.$i18n.t("ID_IN_PROGRESS"),
"OVERDUE": this.$i18n.t("ID_TASK_OVERDUE"),
"DRAFT": this.$i18n.t("ID_IN_DRAFT"),
"PAUSED": this.$i18n.t("ID_PAUSED"),
"UNASSIGNED": this.$i18n.t("ID_UNASSIGNED")
}
};
},
created() {
this.initFilters();
},
mounted() {
this.openDefaultCase();
},
watch: {},
computed: {
/**
* Build our ProcessMaker apiClient
*/
ProcessMaker() {
return window.ProcessMaker;
},
},
updated() {},
beforeCreate() {},
methods: {
/**
* Initialize filters
*/
initFilters() {
let params;
if(this.defaultOption) {
params = utils.getAllUrlParams(this.defaultOption);
if (params && params.openapplicationuid) {
this.$emit("onUpdateFilters",[
{
fieldId: "caseNumber",
filterVar: "caseNumber",
label: "",
options:[],
value: params.openapplicationuid,
autoShow: false
}
]);
}
}
},
/**
* Open a case when the component was mounted
*/
openDefaultCase() {
let params;
if(this.defaultOption) {
params = utils.getAllUrlParams(this.defaultOption);
if (params && params.app_uid && params.del_index) {
this.openCase({
APP_UID: params.app_uid,
DEL_INDEX: params.del_index
});
this.$emit("cleanDefaultOption");
}
//force to search in the parallel tasks
if (params && params.openapplicationuid) {
this.onUpdateFilters({
params: [
{
fieldId: "caseNumber",
filterVar: "caseNumber",
label: "",
options:[],
value: params.openapplicationuid,
autoShow: false
}
],
refresh: false
});
this.$emit("cleanDefaultOption");
}
}
},
/**
* On row click event handler
* @param {object} event
*/
onRowClick(event) {
let self = this;
self.clickCount += 1;
if (self.clickCount === 1) {
self.singleClickTimer = setTimeout(function() {
self.clickCount = 0;
}, 400);
} else if (self.clickCount === 2) {
clearTimeout(self.singleClickTimer);
self.clickCount = 0;
self.openCase(event.row);
}
},
/**
* Get cases todo data
*/
getCasesForVueTable(data) {
let that = this,
dt,
paged,
limit = data.limit,
start = data.page === 1 ? 0 : limit * (data.page - 1),
filters = {};
paged = start + "," + limit;
filters = {
paged: paged,
};
_.forIn(this.filters, function (item, key) {
filters[item.filterVar] = item.value;
});
return new Promise((resolutionFunc, rejectionFunc) => {
api.cases
.draft(filters)
.then((response) => {
dt = that.formatDataResponse(response.data.data);
resolutionFunc({
data: dt,
count: response.data.total,
});
})
.catch((e) => {
rejectionFunc(e);
});
});
},
/**
* Format Response API TODO to grid todo and columns
*/
formatDataResponse(response) {
let data = [];
_.forEach(response, (v) => {
data.push({
CASE_NUMBER: v.APP_NUMBER,
CASE_TITLE: v.DEL_TITLE,
PROCESS_NAME: v.PRO_TITLE,
TASK: [{
TITLE: v.TAS_TITLE,
CODE_COLOR: v.TAS_COLOR,
COLOR: v.TAS_COLOR_LABEL,
DELAYED_TITLE: v.TAS_STATUS === "OVERDUE" ?
this.$i18n.t("ID_DELAYED") + ":" : this.statusTitle[v.TAS_STATUS],
DELAYED_MSG: v.TAS_STATUS === "OVERDUE" ? v.DELAY : ""
}],
PRIORITY: v.DEL_PRIORITY_LABEL,
PRO_UID: v.PRO_UID,
TAS_UID: v.TAS_UID,
DEL_INDEX: v.DEL_INDEX,
APP_UID: v.APP_UID
});
});
return data;
},
/**
* Open selected cases in the inbox
*
* @param {object} item
*/
openCase(item) {
this.$emit("onUpdateDataCase", {
APP_UID: item.APP_UID,
DEL_INDEX: item.DEL_INDEX,
PRO_UID: item.PRO_UID,
TAS_UID: item.TAS_UID,
ACTION: "draft"
});
this.$emit("onUpdatePage", "XCase");
},
/**
* Open case detail from draft
*
* @param {object} item
*/
openCaseDetail(item) {
let that = this;
api.cases.open(_.extend({ ACTION: "todo" }, item)).then(() => {
api.cases.cases_open(_.extend({ ACTION: "todo" }, item)).then(() => {
that.$emit("onUpdateDataCase", {
APP_UID: item.APP_UID,
DEL_INDEX: item.DEL_INDEX,
PRO_UID: item.PRO_UID,
TAS_UID: item.TAS_UID,
APP_NUMBER: item.CASE_NUMBER,
ACTION: "draft"
});
that.$emit("onUpdatePage", "case-detail");
});
});
},
onRemoveFilter(data) {},
onUpdateFilters(data) {
this.$emit("onUpdateFilters", data.params);
if (data.refresh) {
this.$nextTick(() => {
this.$refs["vueTable"].getData();
});
}
},
/**
* update view in component
*/
updateView(){
this.$refs["vueTable"].getData();
}
},
};
</script>
<style>
.v-container-draft {
padding-top: 20px;
padding-bottom: 20px;
padding-left: 50px;
padding-right: 50px;
}
</style>

View File

@@ -0,0 +1,614 @@
<template>
<div id="v-draft" ref="v-draft" class="v-container-draft">
<button-fleft :data="newCase"></button-fleft>
<modal-new-request ref="newRequest"></modal-new-request>
<CasesFilter
:filters="filters"
:title="$t('ID_DRAFT')"
:icon="icon"
@onRemoveFilter="onRemoveFilter"
@onUpdateFilters="onUpdateFilters"
/>
<multiview-header
:data="dataMultiviewHeader"
:dataSubtitle="dataSubtitle"
/>
<settings-popover :options="formatColumnSettings(options.headings)" target="pm-dr-column-settings" @onUpdateColumnSettings="onUpdateColumnSettings" :key="random+1" :selected="formatColumnSelected(columns)"/>
<v-server-table
v-if="typeView === 'GRID'"
:data="tableData"
:columns="columns"
:options="options"
ref="vueTable"
@row-click="onRowClick"
:key="random"
name="draft"
>
<div slot="detail" slot-scope="props">
<div class="btn-default" @click="openCaseDetail(props.row)">
<i class="fas fa-info-circle"></i>
</div>
</div>
<div slot="case_number" slot-scope="props">
{{ props.row.CASE_NUMBER }}
</div>
<div slot="case_title" slot-scope="props">
{{ props.row.CASE_TITLE }}
</div>
<div slot="process_name" slot-scope="props">
{{ props.row.PROCESS_NAME }}
</div>
<div slot="task" slot-scope="props">
<TaskCell :data="props.row.TASK" />
</div>
<div slot="priority" slot-scope="props">{{ props.row.PRIORITY }}</div>
<div slot="actions" slot-scope="props">
<div @click="updateDataEllipsis(props.row)">
<ellipsis :ref="`ellipsis-${props.row.TAS_UID}`" v-if="dataEllipsis" :data="dataEllipsis"> </ellipsis>
</div>
</div>
</v-server-table>
<VueCardView
v-if="typeView === 'CARD'"
:options="optionsVueView"
ref="vueCardView"
>
<div slot="actions" slot-scope="props">
<b-row>
<b-col sm="12">
<div class="v-pm-card-info" @click="openCaseDetail(props.item)">
<i class="fas fa-info-circle"></i>
</div>
</b-col>
<b-col sm="12">
<div class="ellipsis-container" @click="updateDataEllipsis(props.row)">
<ellipsis :ref="`ellipsis-${props.item.TAS_UID}`" v-if="dataEllipsis" :data="dataEllipsis"> </ellipsis>
</div>
</b-col>
</b-row>
</div>
<div slot="case_number" slot-scope="props" class="v-card-text">
<span class="v-card-text-highlight"
>{{ props["headings"][props.column] }} : {{ props["item"]["CASE_NUMBER"] }}</span
>
</div>
<div slot="case_title" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light"
>{{ props["item"]["CASE_TITLE"] }}
</span>
</div>
<div slot="process_name" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light"
>{{ props["item"]["PROCESS_NAME"] }}
</span>
</div>
<div slot="due_date" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light"
>{{ props["item"]["DUE_DATE"] }}
</span>
</div>
<div slot="delegation_date" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light"
>{{ props["item"]["DELEGATION_DATE"] }}
</span>
</div>
<div slot="task" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light">
<TaskCell :data="props.item.TASK" />
</span>
</div>
</VueCardView>
<VueListView
v-if="typeView === 'LIST'"
:options="optionsVueView"
ref="vueListView"
>
<div slot="actions" slot-scope="props">
<b-row>
<b-col sm="12">
<div class="v-pm-card-info" @click="openCaseDetail(props.item)">
<i class="fas fa-info-circle"></i>
</div>
</b-col>
<b-col sm="12">
<div class="ellipsis-container" @click="updateDataEllipsis(props.item)">
<ellipsis :ref="`ellipsis-${props.item.TAS_UID}`" v-if="dataEllipsis" :data="dataEllipsis"> </ellipsis>
</div>
</b-col>
</b-row>
</div>
<div slot="case_number" slot-scope="props" class="v-card-text">
<span class="v-card-text-highlight"
>{{ props["headings"][props.column] }} : {{ props["item"]["CASE_NUMBER"] }}</span
>
</div>
<div slot="case_title" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light"
>{{ props["item"]["CASE_TITLE"] }}
</span>
</div>
<div slot="process_name" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light"
>{{ props["item"]["PROCESS_NAME"] }}
</span>
</div>
<div slot="due_date" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light"
>{{ props["item"]["DUE_DATE"] }}
</span>
</div>
<div slot="delegation_date" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light"
>{{ props["item"]["DELEGATION_DATE"] }}
</span>
</div>
<div slot="task" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light">
<TaskCell :data="props.item.TASK" />
</span>
</div>
</VueListView>
</div>
</template>
<script>
import HeaderCounter from "../../components/home/HeaderCounter.vue";
import ButtonFleft from "../../components/home/ButtonFleft.vue";
import ModalNewRequest from "../ModalNewRequest.vue";
import CasesFilter from "../../components/search/CasesFilter";
import TaskCell from "../../components/vuetable/TaskCell.vue";
import api from "../../api/index";
import utils from "../../utils/utils";
import MultiviewHeader from "../../components/headers/MultiviewHeader.vue";
import VueCardView from "../../components/dataViews/vueCardView/VueCardView.vue";
import VueListView from "../../components/dataViews/vueListView/VueListView.vue";
import defaultMixins from "./defaultMixins";
import Ellipsis from '../../components/utils/ellipsis.vue';
import { Event } from 'vue-tables-2';
export default {
name: "Draft",
mixins: [defaultMixins],
components: {
HeaderCounter,
ButtonFleft,
ModalNewRequest,
TaskCell,
CasesFilter,
Ellipsis,
MultiviewHeader,
VueCardView,
VueListView
},
props: ["defaultOption", "settings"],
data() {
let that = this;
return {
columMap: {
case_number: "APP_NUMBER",
case_title: "DEL_TITLE",
process_name: "PRO_TITLE"
},
newCase: {
title: this.$i18n.t("ID_NEW_CASE"),
class: "btn-success",
onClick: () => {
this.$refs["newRequest"].show();
},
},
filters:
this.settings && this.settings.filters
? this.settings.filters
: {},
columns:
this.settings && this.settings.columns
? this.settings.columns
: [
"detail",
"case_number",
"case_title",
"process_name",
"task",
"priority",
"actions"
],
tableData: [],
icon:"fas fa-edit",
options: {
filterable: false,
headings: {
detail: this.$i18n.t("ID_DETAIL_CASE"),
case_number: this.$i18n.t("ID_MYCASE_NUMBER"),
case_title: this.$i18n.t("ID_CASE_TITLE"),
process_name: this.$i18n.t("ID_PROCESS_NAME"),
task: this.$i18n.t("ID_TASK"),
actions: ""
},
selectable: {
mode: "single",
only: function (row) {
return true;
},
selectAllMode: "page",
programmatic: false,
},
sortable: ['case_number'],
orderBy: this.settings && this.settings.orderBy ? this.settings.orderBy: {},
requestFunction(data) {
return this.$parent.$parent.getCasesForVueTable(data);
},
texts: {
count:this.$i18n.t("ID_SHOWING_FROM_RECORDS_COUNT"),
first: this.$i18n.t("ID_FIRST"),
last: this.$i18n.t("ID_LAST"),
filter: this.$i18n.t("ID_FILTER") + ":",
limit: this.$i18n.t("ID_RECORDS") + ":",
page: this.$i18n.t("ID_PAGE") + ":",
noResults: this.$i18n.t("ID_NO_MATCHING_RECORDS")
},
settings: {
"actions":{
class: "fas fa-cog",
id:"pm-dr-column-settings",
events:{
click(){
that.$root.$emit('bv::show::popover', 'pm-dr-column-settings')
}
}
}
},
},
pmDateFormat: "Y-m-d H:i:s",
clickCount: 0,
singleClickTimer: null,
statusTitle: {
"ON_TIME": this.$i18n.t("ID_IN_PROGRESS"),
"OVERDUE": this.$i18n.t("ID_TASK_OVERDUE"),
"DRAFT": this.$i18n.t("ID_IN_DRAFT"),
"PAUSED": this.$i18n.t("ID_PAUSED"),
"UNASSIGNED": this.$i18n.t("ID_UNASSIGNED")
},
dataEllipsis: {
buttons: {}
},
showEllipsis: false,
dataSubtitle: null
};
},
created() {
this.initFilters();
},
mounted() {
let that = this;
this.openDefaultCase();
// define sort event
Event.$on('vue-tables.draft.sorted', function (data) {
that.$emit("updateSettings", {
data: data,
key: "orderBy",
parent: this.page,
type: "normal",
id: this.id
});
});
},
watch: {
columns: function (val) {
this.$emit("updateSettings", {
data: val,
key: "columns",
parent: this.page,
type: "normal",
id: this.id
});
},
filters: function (val) {
this.$emit("updateSettings", {
data: val,
key: "filters",
parent: this.page,
type: "normal",
id: this.id
});
},
},
computed: {
/**
* Build our ProcessMaker apiClient
*/
ProcessMaker() {
return window.ProcessMaker;
},
},
updated() {},
beforeCreate() {},
methods: {
/**
* Initialize filters
*/
initFilters() {
let params;
if(this.defaultOption) {
params = utils.getAllUrlParams(this.defaultOption);
if (params && params.openapplicationuid) {
this.$emit("onUpdateFilters",[
{
fieldId: "caseNumber",
filterVar: "caseNumber",
label: "",
options:[],
value: params.openapplicationuid,
autoShow: false
}
]);
}
}
},
/**
* Open a case when the component was mounted
*/
openDefaultCase() {
let params;
if(this.defaultOption) {
params = utils.getAllUrlParams(this.defaultOption);
if (params && params.app_uid && params.del_index) {
this.openCase({
APP_UID: params.app_uid,
DEL_INDEX: params.del_index
});
this.$emit("cleanDefaultOption");
}
//force to search in the parallel tasks
if (params && params.openapplicationuid) {
this.onUpdateFilters({
params: [
{
fieldId: "caseNumber",
filterVar: "caseNumber",
label: "",
options:[],
value: params.openapplicationuid,
autoShow: false
}
],
refresh: false
});
this.$emit("cleanDefaultOption");
}
}
},
/**
* On row click event handler
* @param {object} event
*/
onRowClick(event) {
let self = this;
self.clickCount += 1;
if (self.clickCount === 1) {
self.singleClickTimer = setTimeout(function() {
self.clickCount = 0;
}, 400);
} else if (self.clickCount === 2) {
clearTimeout(self.singleClickTimer);
self.clickCount = 0;
self.openCase(event.row);
}
},
/**
* Get cases todo data
*/
getCasesForVueTable(data) {
let that = this,
dt,
paged,
limit = data.limit,
start = data.page === 1 ? 0 : limit * (data.page - 1),
filters = {},
sort = "";
filters = {
limit: limit,
offset: start
};
_.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
.draft(filters)
.then((response) => {
dt = that.formatDataResponse(response.data.data);
resolutionFunc({
data: dt,
count: response.data.total,
});
})
.catch((e) => {
rejectionFunc(e);
});
});
},
/**
* Prepare sort string to be sended in the service
* @param {object} data
* @returns {string}
*/
prepareSortString(data){
let sort = "";
if (data.orderBy && this.columMap[data.orderBy]) {
sort = `${this.columMap[data.orderBy]},${data.ascending === 1 ? "ASC": "DESC"}`;
}
return sort;
},
/**
* Format Response API TODO to grid todo and columns
*/
formatDataResponse(response) {
let data = [];
_.forEach(response, (v) => {
data.push({
CASE_NUMBER: v.APP_NUMBER,
CASE_TITLE: v.DEL_TITLE,
PROCESS_NAME: v.PRO_TITLE,
TASK: [{
TITLE: v.TAS_TITLE,
CODE_COLOR: v.TAS_COLOR,
COLOR: v.TAS_COLOR_LABEL,
DELAYED_TITLE: v.TAS_STATUS === "OVERDUE" ?
this.$i18n.t("ID_DELAYED") + ":" : this.statusTitle[v.TAS_STATUS],
DELAYED_MSG: v.TAS_STATUS === "OVERDUE" ? v.DELAY : ""
}],
PRIORITY: v.DEL_PRIORITY_LABEL,
PRO_UID: v.PRO_UID,
TAS_UID: v.TAS_UID,
DEL_INDEX: v.DEL_INDEX,
APP_UID: v.APP_UID
});
});
return data;
},
/**
* Open selected cases in the inbox
*
* @param {object} item
*/
openCase(item) {
this.$emit("onUpdateDataCase", {
APP_UID: item.APP_UID,
DEL_INDEX: item.DEL_INDEX,
PRO_UID: item.PRO_UID,
TAS_UID: item.TAS_UID,
ACTION: "draft"
});
this.$emit("onUpdatePage", "XCase");
},
/**
* Open case detail from draft
*
* @param {object} item
*/
openCaseDetail(item) {
let that = this;
api.cases.open(_.extend({ ACTION: "todo" }, item)).then(() => {
api.cases.cases_open(_.extend({ ACTION: "todo" }, item)).then(() => {
that.$emit("onUpdateDataCase", {
APP_UID: item.APP_UID,
DEL_INDEX: item.DEL_INDEX,
PRO_UID: item.PRO_UID,
TAS_UID: item.TAS_UID,
APP_NUMBER: item.CASE_NUMBER,
ACTION: "draft"
});
that.$emit("onUpdatePage", "case-detail");
});
});
},
onRemoveFilter(data) {},
onUpdateFilters(data) {
this.filters = data.params;
if (data.refresh) {
this.$nextTick(() => {
if (this.typeView === "GRID") {
this.$refs["vueTable"].getData();
}
if (this.typeView === "CARD") {
this.$refs["vueCardView"].getData();
}
if (this.typeView === "LIST") {
this.$refs["vueListView"].getData();
}
});
}
},
/**
* update view in component
*/
updateView(){
if (this.typeView === "GRID") {
this.$refs["vueTable"].getData();
}
if (this.typeView === "CARD") {
this.$refs["vueCardView"].getData();
}
if (this.typeView === "LIST") {
this.$refs["vueListView"].getData();
}
},
/**
* Show options in the ellipsis
* @param {object} data
*/
updateDataEllipsis(data) {
let that = this;
this.showEllipsis = !this.showEllipsis;
if (this.showEllipsis) {
this.dataEllipsis = {
buttons: {
open: {
name: "open",
icon: "far fa-edit",
fn: function() {
that.openCase(data);
}
},
note: {
name: "case note",
icon: "far fa-comments",
fn: function() {
that.openCaseDetail(data);
}
},
}
}
}
},
},
};
</script>
<style>
.v-container-draft {
padding-top: 20px;
padding-bottom: 20px;
padding-left: 50px;
padding-right: 50px;
}
.ellipsis-container {
margin-top: 5em;
}
</style>

View File

@@ -0,0 +1,170 @@
import api from "../../api/index";
export default {
data() {
let that = this;
return {
typeView: "GRID",
random: 1,
dataMultiviewHeader: {
actions: [
{
id: "view-grid",
title: "Grid",
onClick(action) {
that.typeView = "GRID";
},
icon: "fas fa-table",
},
{
id: "view-list",
title: "List",
onClick(action) {
that.typeView = "LIST";
},
icon: "fas fa-list",
},
{
id: "view-card",
title: "Card",
onClick(action) {
that.typeView = "CARD";
},
icon: "fas fa-th",
},
],
},
optionsVueView: {
limit: 10,
dblClick:(event, item, options)=>{
this.openCase(item);
},
headings: {
detail: "",
case_number: this.$i18n.t("ID_MYCASE_NUMBER"),
case_title: this.$i18n.t("ID_CASE_TITLE"),
process_name: this.$i18n.t("ID_PROCESS_NAME"),
task: this.$i18n.t("ID_TASK"),
current_user: this.$i18n.t("ID_CURRENT_USER"),
due_date: this.$i18n.t("ID_DUE_DATE"),
delegation_date: this.$i18n.t("ID_DELEGATION_DATE"),
priority: this.$i18n.t("ID_PRIORITY")
},
columns: [
"case_number",
"case_title",
"process_name",
"due_date",
"delegation_date",
"priority",
"task"
],
requestFunction(data) {
return that.getCases(data);
},
requestFunctionViewMore(data) {
return that.getCasesViewMore(data);
}
}
}
},
created: function () {
},
methods: {
/**
* Get cases for Vue Card View
*/
getCases(data) {
let that = this,
dt,
filters = {};
_.forIn(this.filters, function (item, key) {
filters[item.filterVar] = item.value;
});
return new Promise((resolutionFunc, rejectionFunc) => {
api.cases
.draft(filters)
.then((response) => {
dt = that.formatDataResponse(response.data.data);
resolutionFunc({
data: dt,
count: response.data.total,
});
})
.catch((e) => {
rejectionFunc(e);
});
});
},
/**
* Get cases for Vue Card View
*/
getCasesViewMore(data) {
let that = this,
dt,
paged,
limit = data.limit,
start = data.page === 1 ? 0 : limit * (data.page - 1),
filters = {};
filters = {
limit: limit,
offset: start
};
_.forIn(this.filters, function (item, key) {
if (filters && item.value) {
filters[item.filterVar] = item.value;
}
});
return new Promise((resolutionFunc, rejectionFunc) => {
api.cases
.draft(filters)
.then((response) => {
dt = that.formatDataResponse(response.data.data);
resolutionFunc({
data: dt,
count: response.data.total,
});
})
.catch((e) => {
rejectionFunc(e);
});
});
},
/**
* Format columns for custom columns
* @param {*} headings
* @returns
*/
formatColumnSettings(headings) {
let res=[];
_.forEach(headings, function(value, key) {
if(key != "actions"){
res.push({value,key});
}
});
return res;
},
/**
* Formating the columns selected
* @param {*} columns
* @returns
*/
formatColumnSelected(columns) {
let cols = _.clone(columns);
cols.pop();
return cols;
},
/**
* Event handler when update the settings columns
* @param {*} columns
*/
onUpdateColumnSettings(columns) {
let cols = columns;
if(_.findIndex(cols, 'actions') == -1){
cols.push("actions");
}
this.columns = cols;
this.random = _.random(0, 10000000000);
}
}
}

View File

@@ -0,0 +1,4 @@
import Vue from 'vue'
const eventBus = new Vue()
export default eventBus

View File

@@ -20,11 +20,13 @@
<component
v-bind:is="page"
ref="component"
:filters="filters"
:id="pageId"
:pageUri="pageUri"
:name="pageName"
:defaultOption="defaultOption"
:settings="settings"
:filters="filters"
:data="pageData"
@onSubmitFilter="onSubmitFilter"
@onRemoveFilter="onRemoveFilter"
@onUpdatePage="onUpdatePage"
@@ -32,27 +34,31 @@
@onLastPage="onLastPage"
@onUpdateFilters="onUpdateFilters"
@cleanDefaultOption="cleanDefaultOption"
@updateSettings="updateSettings"
></component>
</div>
</div>
</template>
<script>
import CustomSidebar from "./../components/menu/CustomSidebar";
import MyCases from "./MyCases";
import CustomSidebarMenuItem from "./../components/menu/CustomSidebarMenuItem";
import MyCases from "./MyCases/MyCases.vue";
import MyDocuments from "./MyDocuments";
import Todo from "./Todo";
import Draft from "./Draft";
import Paused from "./Paused";
import Unassigned from "./Unassigned";
import Inbox from "./Inbox/Inbox.vue";
import Paused from "./Paused/Paused.vue";
import Draft from "./Draft/Draft.vue";
import Unassigned from "./Unassigned/Unassigned.vue";
import TaskMetrics from "./TaskMetrics/TaskMetrics.vue";
import BatchRouting from "./BatchRouting";
import CaseDetail from "./CaseDetail";
import XCase from "./XCase";
import TaskReassignments from "./TaskReassignments";
import AdvancedSearch from "./AdvancedSearch";
import AdvancedSearch from "./AdvancedSearch/AdvancedSearch.vue";
import LegacyFrame from "./LegacyFrame";
import CustomCaseList from "./CustomCaseList/CustomCaseList.vue"
import api from "./../api/index";
import eventBus from './EventBus/eventBus'
export default {
name: "Home",
components: {
@@ -63,12 +69,14 @@ export default {
BatchRouting,
TaskReassignments,
XCase,
Todo,
Inbox,
Draft,
Paused,
Unassigned,
CaseDetail,
LegacyFrame
LegacyFrame,
TaskMetrics,
CustomCaseList
},
data() {
return {
@@ -85,11 +93,16 @@ export default {
pageName: null,
pageUri: null,
filters: null,
config: {
id: window.config.userId || "1",
name: "userConfig",
setting: {}
},
menuMap: {
CASES_MY_CASES: "MyCases",
CASES_SENT: "MyCases",
CASES_SEARCH: "advanced-search",
CASES_INBOX: "todo",
CASES_INBOX: "inbox",
CASES_DRAFT: "draft",
CASES_PAUSED: "paused",
CASES_SELFSERVICE: "unassigned",
@@ -97,17 +110,38 @@ export default {
CASES_TO_REASSIGN: "task-reassignments",
CASES_FOLDERS: "my-documents"
},
defaultOption: window.config.defaultOption || ''
defaultOption: window.config.defaultOption || '',
pageData: {},
settings: {}
};
},
mounted() {
let that = this;
this.onResize();
this.getMenu();
this.getUserSettings();
this.listenerIframe();
window.setInterval(
this.setCounter,
this.getHighlight,
parseInt(window.config.FORMATS.casesListRefreshTime) * 1000
);
// adding eventBus listener
eventBus.$on('sort-menu', (data) => {
let newData = [];
data.forEach(item => newData.push({id: item.id}));
that.updateSettings({
data: newData,
key: "customCaseListOrder",
parent: this.page,
type: "normal",
id: this.id
});
});
eventBus.$on('home-update-page', (data) => {
that.onUpdatePage(data);
});
eventBus.$on('home-update-datacase', (data) => {
that.onUpdateDataCase(data);
});
},
methods: {
/**
@@ -124,7 +158,7 @@ export default {
eventer(messageEvent, function(e) {
if ( e.data === "redirect=todo" || e.message === "redirect=todo"){
that.page = "todo";
that.page = "inbox";
}
if ( e.data === "update=debugger" || e.message === "update=debugger"){
if(that.$refs["component"].updateView){
@@ -142,12 +176,83 @@ export default {
.then((response) => {
this.setDefaultCasesMenu(response.data);
this.menu = this.mappingMenu(this.setDefaultIcon(response.data));
this.setCounter();
this.getHighlight();
})
.catch((e) => {
console.error(e);
});
},
/**
* Gets the user config
*/
getUserSettings() {
api.config
.get({
id: this.config.id,
name: this.config.name
})
.then((response) => {
if(response.data && response.data.status === 404) {
this.createUserSettings();
} else if (response.data) {
this.config = response.data;
this.getMenu();
}
})
.catch((e) => {
console.error(e);
});
},
/**
* Creates the user config service
*/
createUserSettings() {
api.config
.post(this.config)
.then((response) => {
if (response.data) {
this.config = response.data;
this.getMenu();
}
})
.catch((e) => {
console.error(e);
});
},
/**
* Update the user config service
* @param {object} params
*/
updateSettings (params){
if (params.type === "custom") {
if (!this.config.setting[params.parent]) {
this.config.setting[params.parent] = {};
}
if (!this.config.setting[params.parent]["customCaseList"]) {
this.config.setting[params.parent]["customCaseList"] = {};
}
if (!this.config.setting[params.parent].customCaseList[params.id]) {
this.config.setting[params.parent].customCaseList[params.id] = {}
}
this.config.setting[params.parent].customCaseList[params.id][params.key] = params.data;
} else {
if (!this.config.setting[this.page]) {
this.config.setting[this.page] = {};
}
this.config.setting[this.page][params.key] = params.data;
}
api.config
.put(this.config)
.then((response) => {
if (response.data) {
//TODO success response
}
})
.catch((e) => {
console.error(e);
});
},
/**
* Set default cases menu option
*/
@@ -161,6 +266,7 @@ export default {
} else {
this.page = "MyCases";
}
this.settings = this.config.setting[this.page];
this.lastPage = this.page;
},
/**
@@ -170,18 +276,92 @@ export default {
mappingMenu(data) {
var i,
j,
that = this,
newData = data,
auxId;
for (i = 0; i < data.length; i += 1) {
auxId = data[i].id || "";
auxId = data[i].page || "";
if (auxId !== "" && this.menuMap[auxId]) {
newData[i].id = this.menuMap[auxId];
newData[i].page = this.menuMap[auxId];
} else if (newData[i].href) {
newData[i].id = "LegacyFrame";
newData[i].page = "LegacyFrame";
}
// Tasks group need pie chart icon
if (data[i].header && data[i].id === "FOLDERS") {
data[i] = {
component: CustomSidebarMenuItem,
props: {
isCollapsed: this.collapsed? true: false,
item: {
header: data[i].header,
title: data[i].title,
hiddenOnCollapse: data[i].hiddenOnCollapse,
icon: 'pie-chart-fill',
onClick: function (item) {
that.onUpdatePage("task-metrics");
}
}
}
}
}
if (data[i].customCasesList) {
data[i]["child"] = this.sortCustomCasesList(
data[i].customCasesList,
this.config.setting[this.page] &&
this.config.setting[this.page].customCaseListOrder
? this.config.setting[this.page].customCaseListOrder
: []
);
data[i]["sortable"] = data[i].customCasesList.length > 1;
data[i]["sortIcon"] = "gear-fill";
data[i]['highlight'] = false;
data[i] = {
component: CustomSidebarMenuItem,
props: {
isCollapsed: this.collapsed? true: false,
item: data[i]
}
};
}
}
return newData;
},
/**
* Sort the custom case list menu items
* @param {array} list
* @param {array} ref
* @returns {array}
*/
sortCustomCasesList(list, ref) {
let item,
newList = [],
temp = [];
if (ref && ref.length) {
ref.forEach(function (menu) {
item = list.find(x => x.id === menu.id);
if (item) {
newList.push(item);
}
})
} else {
return list;
}
temp = list.filter(this.comparerById(newList));
return [...newList, ...temp];
},
/**
* Util to compare an array by id
* @param {array} otherArray
* @returns {object}
*/
comparerById(otherArray){
return function(current){
return otherArray.filter(function(other){
return other.id == current.id
}).length == 0;
}
},
/**
* Set a default icon if the item doesn't have one
*/
@@ -202,7 +382,7 @@ export default {
this.defaultOption = "";
},
OnClickSidebarItem(item) {
if (item.item.page && item.item.page === "/advanced-search") {
if (item.item.page && item.item.page === "advanced-search") {
this.page = "advanced-search";
this.filters = item.item.filters;
this.pageId = item.item.id;
@@ -212,11 +392,28 @@ export default {
this.filters = [];
this.pageId = null;
this.pageUri = item.item.href;
this.page = item.item.id || "MyCases";
if (this.page === this.lastPage
&& this.$refs["component"]
this.page = item.item.page || "MyCases";
this.settings = this.config.setting[this.page];
if (!this.menuMap[item.item.id]) {
this.page = "custom-case-list";
this.pageData = {
pageUri: item.item.pageUri,
pageParent: item.item.page,
pageName: item.item.title,
pageIcon: item.item.icon,
customListId: item.item.id,
color: item.item.colorScreen
}
if (this.config.setting[item.item.page] && this.config.setting[item.item.page]["customCaseList"]) {
this.settings = this.config.setting[item.item.page]["customCaseList"][item.item.id];
} else {
this.settings = {};
}
}
if (this.page === this.lastPage
&& this.$refs["component"]
&& this.$refs["component"].updateView) {
this.$refs["component"].updateView();
this.$refs["component"].updateView(this.pageData);
}
this.lastPage = this.page;
}
@@ -333,8 +530,37 @@ export default {
if (index !== -1) advSearch.child.splice(index, 1);
}
},
/**
* Update filters handler
*/
onUpdateFilters(filters) {
this.filters = filters;
},
/**
* Service to get Highlight
*/
getHighlight() {
let that = this;
if (that.menu.length > 0) {
api.menu
.getHighlight()
.then((response) => {
var i,
dataHighlight = [];
for (i = 0; i < response.data.length; i += 1) {
if (response.data[i].highlight) {
dataHighlight.push({
id: that.menuMap[response.data[i].item],
highlight: response.data[i].highlight
});
}
}
eventBus.$emit('highlight', dataHighlight);
})
.catch((e) => {
console.error(e);
});
}
}
}
};

View File

@@ -0,0 +1,748 @@
<template>
<div id="v-todo" ref="v-todo" class="v-container-todo">
<button-fleft :data="newCase"></button-fleft>
<modal-new-request ref="newRequest"></modal-new-request>
<ModalPauseCase ref="modal-pause-case"></ModalPauseCase>
<ModalReassignCase ref="modal-reassign-case"></ModalReassignCase>
<CasesFilter
:filters="filters"
:title="$t('ID_INBOX')"
:icon="icon"
@onRemoveFilter="onRemoveFilter"
@onUpdateFilters="onUpdateFilters"
/>
<multiview-header
:data="dataMultiviewHeader"
:dataSubtitle="dataSubtitle"
/>
<settings-popover :options="formatColumnSettings(options.headings)" target="pm-dr-column-settings" @onUpdateColumnSettings="onUpdateColumnSettings" :key="random+1" :selected="formatColumnSelected(columns)"/>
<v-server-table
v-if="typeView === 'GRID'"
:data="tableData"
:columns="columns"
:options="options"
ref="vueTable"
@row-click="onRowClick"
:key="random"
name="todo"
>
<div slot="detail" slot-scope="props">
<div class="btn-default" @click="openCaseDetail(props.row)">
<i class="fas fa-info-circle"></i>
</div>
</div>
<div slot="case_number" slot-scope="props">
{{ props.row.CASE_NUMBER }}
</div>
<div slot="case_title" slot-scope="props">
{{ props.row.CASE_TITLE }}
</div>
<div slot="process_name" slot-scope="props">
{{ props.row.PROCESS_NAME }}
</div>
<div slot="task" slot-scope="props">
<TaskCell :data="props.row.TASK" />
</div>
<div slot="send_by" slot-scope="props">
<CurrentUserCell :data="props.row.USER_DATA" />
</div>
<div slot="current_user" slot-scope="props">
{{ props.row.USERNAME_DISPLAY_FORMAT }}
</div>
<div slot="due_date" slot-scope="props">
{{ props.row.DUE_DATE }}
</div>
<div slot="delegation_date" slot-scope="props">
{{ props.row.DELEGATION_DATE }}
</div>
<div slot="priority" slot-scope="props">{{ props.row.PRIORITY }}</div>
<div slot="actions" slot-scope="props">
<div @click="updateDataEllipsis(props.row)">
<ellipsis :ref="`ellipsis-${props.row.TAS_UID}`" v-if="dataEllipsis" :data="dataEllipsis"> </ellipsis>
</div>
</div>
</v-server-table>
<VueCardView
v-if="typeView === 'CARD'"
:options="optionsVueView"
ref="vueCardView"
>
<div slot="actions" slot-scope="props">
<b-row>
<b-col sm="12">
<div class="v-pm-card-info" @click="openCaseDetail(props.item)">
<i class="fas fa-info-circle"></i>
</div>
</b-col>
<b-col sm="12">
<div class="ellipsis-container" @click="updateDataEllipsis(props.item)">
<ellipsis :ref="`ellipsis-${props.item.TAS_UID}`" v-if="dataEllipsis" :data="dataEllipsis"> </ellipsis>
</div>
</b-col>
</b-row>
</div>
<div slot="case_number" slot-scope="props" class="v-card-text">
<span class="v-card-text-highlight"
>{{ props["headings"][props.column] }} : {{ props["item"]["CASE_NUMBER"] }}</span
>
</div>
<div slot="case_title" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light"
>{{ props["item"]["CASE_TITLE"] }}
</span>
</div>
<div slot="process_name" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light"
>{{ props["item"]["PROCESS_NAME"] }}
</span>
</div>
<div slot="due_date" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light"
>{{ props["item"]["DUE_DATE"] }}
</span>
</div>
<div slot="delegation_date" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light"
>{{ props["item"]["DELEGATION_DATE"] }}
</span>
</div>
<div slot="task" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light">
<TaskCell :data="props.item.TASK" />
</span>
</div>
<div slot="send_by" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light">
<CurrentUserCell :data="props.item.USER_DATA" />
</span>
</div>
</VueCardView>
<VueListView
v-if="typeView === 'LIST'"
:options="optionsVueView"
ref="vueListView"
>
<div slot="actions" slot-scope="props">
<b-row>
<b-col sm="12">
<div class="v-pm-card-info" @click="openCaseDetail(props.item)">
<i class="fas fa-info-circle"></i>
</div>
</b-col>
<b-col sm="12">
<div class="ellipsis-container" @click="updateDataEllipsis(props.item)">
<ellipsis :ref="`ellipsis-${props.item.TAS_UID}`" v-if="dataEllipsis" :data="dataEllipsis"> </ellipsis>
</div>
</b-col>
</b-row>
</div>
<div ref="text" slot="case_number" slot-scope="props" class="v-card-text">
<span class="v-card-text-highlight"
>{{ props["headings"][props.column] }} : {{ props["item"]["CASE_NUMBER"] }}</span
>
</div>
<div slot="case_title" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light"
>{{ props["item"]["CASE_TITLE"] }}
</span>
</div>
<div slot="process_name" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light"
>{{ props["item"]["PROCESS_NAME"] }}
</span>
</div>
<div slot="due_date" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light"
>{{ props["item"]["DUE_DATE"] }}
</span>
</div>
<div slot="delegation_date" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light"
>{{ props["item"]["DELEGATION_DATE"] }}
</span>
</div>
<div slot="task" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light">
<TaskCell :data="props.item.TASK" />
</span>
</div>
<div slot="send_by" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light">
<CurrentUserCell :data="props.item.USER_DATA" />
</span>
</div>
</VueListView>
</div>
</template>
<script>
import HeaderCounter from "../../components/home/HeaderCounter.vue";
import ButtonFleft from "../../components/home/ButtonFleft.vue";
import ModalNewRequest from "../ModalNewRequest.vue";
import TaskCell from "../../components/vuetable/TaskCell.vue";
import CasesFilter from "../../components/search/CasesFilter";
import api from "../../api/index";
import utils from "../../utils/utils";
import MultiviewHeader from "../../components/headers/MultiviewHeader.vue";
import VueCardView from "../../components/dataViews/vueCardView/VueCardView.vue";
import VueListView from "../../components/dataViews/vueListView/VueListView.vue";
import defaultMixins from "./defaultMixins";
import Ellipsis from '../../components/utils/ellipsis.vue';
import ModalPauseCase from '../modal/ModalPauseCase.vue';
import ModalReassignCase from '../modal/ModalReassignCase.vue';
import { Event } from 'vue-tables-2';
import CurrentUserCell from "../../components/vuetable/CurrentUserCell.vue";
export default {
name: "Inbox",
mixins: [defaultMixins],
components: {
HeaderCounter,
ButtonFleft,
ModalNewRequest,
TaskCell,
CasesFilter,
MultiviewHeader,
VueCardView,
VueListView,
Ellipsis,
ModalPauseCase,
ModalReassignCase,
CurrentUserCell,
},
props: ["defaultOption", "settings"],
data() {
let that = this;
return {
columMap: {
case_number: "APP_NUMBER",
case_title: "DEL_TITLE",
process_name: "PRO_TITLE"
},
newCase: {
title: this.$i18n.t("ID_NEW_CASE"),
class: "btn-success",
onClick: () => {
this.$refs["newRequest"].show();
},
},
filters:
this.settings && this.settings.filters
? this.settings.filters
: {},
columns:
this.settings && this.settings.columns
? this.settings.columns
: [
"detail",
"case_number",
"case_title",
"process_name",
"task",
"send_by",
"due_date",
"delegation_date",
"priority",
"actions"
],
tableData: [],
icon:"fas fa-check-circle",
options: {
filterable: false,
headings: {
detail: this.$i18n.t("ID_DETAIL_CASE"),
case_number: this.$i18n.t("ID_MYCASE_NUMBER"),
case_title: this.$i18n.t("ID_CASE_TITLE"),
process_name: this.$i18n.t("ID_PROCESS_NAME"),
task: this.$i18n.t("ID_TASK"),
send_by: this.$i18n.t("ID_SEND_BY"),
due_date: this.$i18n.t("ID_DUE_DATE"),
delegation_date: this.$i18n.t("ID_DELEGATION_DATE"),
priority: this.$i18n.t("ID_PRIORITY"),
actions: "",
},
texts: {
count: this.$i18n.t("ID_SHOWING_FROM_RECORDS_COUNT"),
first: this.$i18n.t("ID_FIRST"),
last: this.$i18n.t("ID_LAST"),
filter: this.$i18n.t("ID_FILTER") + ":",
limit: this.$i18n.t("ID_RECORDS") + ":",
page: this.$i18n.t("ID_PAGE") + ":",
noResults: this.$i18n.t("ID_NO_MATCHING_RECORDS"),
},
selectable: {
mode: "single",
only: function (row) {
return true;
},
selectAllMode: "page",
programmatic: false,
},
sortable: ['case_number'],
orderBy: this.settings && this.settings.orderBy ? this.settings.orderBy: {},
requestFunction(data) {
return this.$parent.$parent.getCasesForVueTable(data);
},
settings: {
"actions":{
class: "fas fa-cog",
id:"pm-dr-column-settings",
events:{
click(){
that.$root.$emit('bv::show::popover', 'pm-dr-column-settings')
}
}
}
},
},
pmDateFormat: "Y-m-d H:i:s",
clickCount: 0,
singleClickTimer: null,
statusTitle: {
ON_TIME: this.$i18n.t("ID_IN_PROGRESS"),
OVERDUE: this.$i18n.t("ID_TASK_OVERDUE"),
DRAFT: this.$i18n.t("ID_IN_DRAFT"),
PAUSED: this.$i18n.t("ID_PAUSED"),
UNASSIGNED: this.$i18n.t("ID_UNASSIGNED"),
},
dataEllipsis: {
buttons: {}
},
showEllipsis: false,
dataSubtitle: null
};
},
created() {
this.initFilters();
},
mounted() {
let that = this;
// force to open case
this.openDefaultCase();
// define sort event
Event.$on('vue-tables.todo.sorted', function (data) {
that.$emit("updateSettings", {
data: data,
key: "orderBy",
parent: this.page,
type: "normal",
id: this.id
});
});
},
watch: {
columns: function (val) {
this.$emit("updateSettings", {
data: val,
key: "columns",
parent: this.page,
type: "normal",
id: this.id
});
},
filters: function (val) {
this.$emit("updateSettings", {
data: val,
key: "filters",
parent: this.page,
type: "normal",
id: this.id
});
},
},
computed: {
/**
* Build our ProcessMaker apiClient
*/
ProcessMaker() {
return window.ProcessMaker;
},
},
updated() {},
beforeCreate() {},
methods: {
/**
* Initialize filters
*/
initFilters() {
let params;
if (this.defaultOption) {
params = utils.getAllUrlParams(this.defaultOption);
if (params && params.openapplicationuid) {
this.$emit("onUpdateFilters", [
{
fieldId: "caseNumber",
filterVar: "caseNumber",
label: "",
options: [],
value: params.openapplicationuid,
autoShow: false,
},
]);
}
}
},
/**
* Open a case when the component was mounted
*/
openDefaultCase() {
let params;
if (this.defaultOption) {
params = utils.getAllUrlParams(this.defaultOption);
if (params && params.app_uid && params.del_index) {
this.openCase({
APP_UID: params.app_uid,
DEL_INDEX: params.del_index,
});
this.$emit("cleanDefaultOption");
}
//force to search in the parallel tasks
if (params && params.openapplicationuid) {
this.onUpdateFilters({
params: [
{
fieldId: "caseNumber",
filterVar: "caseNumber",
label: "",
options: [],
value: params.openapplicationuid,
autoShow: false,
},
],
refresh: false,
});
this.$emit("cleanDefaultOption");
}
}
},
/**
* On row click event handler
* @param {object} event
*/
onRowClick(event) {
let self = this;
self.clickCount += 1;
if (self.clickCount === 1) {
self.singleClickTimer = setTimeout(function () {
self.clickCount = 0;
}, 400);
} else if (self.clickCount === 2) {
clearTimeout(self.singleClickTimer);
self.clickCount = 0;
self.openCase(event.row);
}
},
/**
* Get cases todo data
*/
getCasesForVueTable(data) {
let that = this,
dt,
paged,
limit = data.limit,
start = data.page === 1 ? 0 : limit * (data.page - 1),
filters = {},
sort = "";
filters = {
limit: limit,
offset: start
};
_.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
.todo(filters)
.then((response) => {
dt = that.formatDataResponse(response.data.data);
resolutionFunc({
data: dt,
count: response.data.total,
});
})
.catch((e) => {
rejectionFunc(e);
});
});
},
/**
* Prepare sort string to be sended in the service
* @param {object} data
* @returns {string}
*/
prepareSortString(data){
let sort = "";
if (data.orderBy && this.columMap[data.orderBy]) {
sort = `${this.columMap[data.orderBy]},${data.ascending === 1 ? "ASC": "DESC"}`;
}
return sort;
},
/**
* Format Response API TODO to grid todo and columns
*/
formatDataResponse(response) {
let data = [];
_.forEach(response, (v) => {
data.push({
CASE_NUMBER: v.APP_NUMBER,
CASE_TITLE: v.DEL_TITLE,
PROCESS_NAME: v.PRO_TITLE,
TASK: [
{
TITLE: v.TAS_TITLE,
CODE_COLOR: v.TAS_COLOR,
COLOR: v.TAS_COLOR_LABEL,
DELAYED_TITLE:
v.TAS_STATUS === "OVERDUE"
? this.$i18n.t("ID_DELAYED") + ":"
: this.statusTitle[v.TAS_STATUS],
DELAYED_MSG: v.TAS_STATUS === "OVERDUE" ? v.DELAY : "",
},
],
USER_DATA: this.formatUser(v.SEND_BY_INFO),
USERNAME_DISPLAY_FORMAT: utils.userNameDisplayFormat({
userName: v.USR_LASTNAME,
firstName: v.USR_LASTNAME,
lastName: v.USR_LASTNAME,
format: window.config.FORMATS.format || null,
}),
DUE_DATE: v.DEL_TASK_DUE_DATE_LABEL,
DELEGATION_DATE: v.DEL_DELEGATE_DATE_LABEL,
PRIORITY: v.DEL_PRIORITY_LABEL,
DEL_INDEX: v.DEL_INDEX,
APP_UID: v.APP_UID,
PRO_UID: v.PRO_UID,
TAS_UID: v.TAS_UID,
});
});
return data;
},
/**
* Set the format to show user's information
* @return {array} dataFormat
*/
formatUser(data) {
var dataFormat = [],
userDataFormat;
userDataFormat = utils.userNameDisplayFormat({
userName: data.user_tooltip.usr_firstname,
firstName: data.user_tooltip.usr_lastname,
lastName: data.user_tooltip.usr_username,
format: window.config.FORMATS.format || null
});
dataFormat.push({
USERNAME_DISPLAY_FORMAT: userDataFormat,
EMAIL: data.user_tooltip.usr_email,
POSITION: data.user_tooltip.usr_position,
AVATAR: userDataFormat !== "" ? window.config.SYS_SERVER_AJAX +
window.config.SYS_URI +
`users/users_ViewPhotoGrid?pUID=${data.user_tooltip.usr_id}` : "",
UNASSIGNED: userDataFormat !== "" ? true : false
});
return dataFormat;
},
/**
* Open selected cases in the inbox
*
* @param {object} item
*/
openCase(item) {
this.$emit("onUpdateDataCase", {
APP_UID: item.APP_UID,
DEL_INDEX: item.DEL_INDEX,
PRO_UID: item.PRO_UID,
TAS_UID: item.TAS_UID,
ACTION: "todo",
});
this.$emit("onUpdatePage", "XCase");
},
/**
* Open case detail
*
* @param {object} item
*/
openCaseDetail(item) {
let that = this;
api.cases.open(_.extend({ ACTION: "todo" }, item)).then(() => {
api.cases.cases_open(_.extend({ ACTION: "todo" }, item)).then(() => {
that.$emit("onUpdateDataCase", {
APP_UID: item.APP_UID,
DEL_INDEX: item.DEL_INDEX,
PRO_UID: item.PRO_UID,
TAS_UID: item.TAS_UID,
APP_NUMBER: item.CASE_NUMBER,
ACTION: "todo",
});
that.$emit("onUpdatePage", "case-detail");
});
});
},
onRemoveFilter(data) {},
onUpdateFilters(data) {
this.filters = data.params;
if (data.refresh) {
this.$nextTick(() => {
if (this.typeView === "GRID") {
this.$refs["vueTable"].getData();
}
if (this.typeView === "CARD") {
this.$refs["vueCardView"].getData();
}
if (this.typeView === "LIST") {
this.$refs["vueListView"].getData();
}
});
}
},
/**
* update view in component
*/
updateView() {
if (this.typeView === "GRID") {
this.$refs["vueTable"].getData();
}
if (this.typeView === "CARD") {
this.$refs["vueCardView"].getData();
}
if (this.typeView === "LIST") {
this.$refs["vueListView"].getData();
}
},
/**
* Show modal to pause a case
* @param {objec} data
*/
showModalPause(data) {
this.$refs["modal-pause-case"].data = data;
this.$refs["modal-pause-case"].show();
},
/**
* Show modal to reassign a case
* @param {objec} data
*/
showModalReassign(data) {
this.$refs["modal-reassign-case"].data = data;
this.$refs["modal-reassign-case"].show();
},
/**
* Show options in the ellipsis
* @param {objec} data
*/
updateDataEllipsis(data) {
let that = this;
this.showEllipsis = !this.showEllipsis;
if (this.showEllipsis) {
this.dataEllipsis = {
buttons: {
open: {
name: "open",
icon: "far fa-edit",
fn: function() {
that.openCase(data)
}
},
note: {
name: "case note",
icon: "far fa-comments",
fn: function() {
that.openCaseDetail(data);
}
},
reassign: {
name: "reassign case",
icon: "fas fa-undo",
fn: function() {
that.showModalReassign(data);
}
},
pause: {
name: "pause case",
icon: "far fa-pause-circle",
fn: function() {
that.showModalPause(data);
}
}
}
}
}
},
},
};
</script>
<style>
.v-container-todo {
padding-top: 20px;
padding-bottom: 20px;
padding-left: 50px;
padding-right: 50px;
}
.VueTables__limit {
display: none;
}
.v-card-text-dark {
color: #343944;
display: inline-block;
}
.v-card-text-highlight {
color: #313541;
display: inline-block;
}
.v-card-text-light {
color: #313541;
display: inline-block;
}
.ellipsis-container {
margin-top: 5em;
}
.v-pm-card-info{
float: right;
}
</style>

View File

@@ -0,0 +1,172 @@
import _ from "lodash";
import api from "../../api/index";
export default {
data() {
let that = this;
return {
typeView: "GRID",
random: 1,
dataMultiviewHeader: {
actions: [
{
id: "view-grid",
title: "Grid",
onClick(action) {
that.typeView = "GRID";
},
icon: "fas fa-table",
},
{
id: "view-list",
title: "List",
onClick(action) {
that.typeView = "LIST";
},
icon: "fas fa-list",
},
{
id: "view-card",
title: "Card",
onClick(action) {
that.typeView = "CARD";
},
icon: "fas fa-th",
},
],
},
optionsVueView: {
limit: 10,
dblClick: (event, item, options) => {
this.openCase(item);
},
headings: {
case_number: this.$i18n.t("ID_MYCASE_NUMBER"),
case_title: this.$i18n.t("ID_CASE_TITLE"),
process_name: this.$i18n.t("ID_PROCESS_NAME"),
task: this.$i18n.t("ID_TASK"),
send_by: this.$i18n.t("ID_SEND_BY"),
current_user: this.$i18n.t("ID_CURRENT_USER"),
due_date: this.$i18n.t("ID_DUE_DATE"),
delegation_date: this.$i18n.t("ID_DELEGATION_DATE"),
priority: this.$i18n.t("ID_PRIORITY")
},
columns: [
"case_number",
"case_title",
"process_name",
"due_date",
"delegation_date",
"priority",
"task",
"send_by",
],
requestFunction(data) {
return that.getCases(data);
},
requestFunctionViewMore(data) {
return that.getCasesViewMore(data);
}
}
}
},
created: function () {
},
methods: {
/**
* Get cases for Vue Card View
*/
getCases(data) {
let that = this,
dt,
filters = {};
_.forIn(this.filters, function (item, key) {
filters[item.filterVar] = item.value;
});
return new Promise((resolutionFunc, rejectionFunc) => {
api.cases
.todo(filters)
.then((response) => {
dt = that.formatDataResponse(response.data.data);
resolutionFunc({
data: dt,
count: response.data.total,
});
})
.catch((e) => {
rejectionFunc(e);
});
});
},
/**
* Get cases for Vue Card View
*/
getCasesViewMore(data) {
let that = this,
dt,
paged,
limit = data.limit,
start = data.page === 1 ? 0 : limit * (data.page - 1),
filters = {};
filters = {
limit: limit,
offset: start
};
_.forIn(this.filters, function (item, key) {
if (filters && item.value) {
filters[item.filterVar] = item.value;
}
});
return new Promise((resolutionFunc, rejectionFunc) => {
api.cases
.todo(filters)
.then((response) => {
dt = that.formatDataResponse(response.data.data);
resolutionFunc({
data: dt,
count: response.data.total,
});
})
.catch((e) => {
rejectionFunc(e);
});
});
},
/**
* Format columns for custom columns
* @param {*} headings
* @returns
*/
formatColumnSettings(headings) {
let res = [];
_.forEach(headings, function (value, key) {
if (key != "actions") {
res.push({ value, key });
}
});
return res;
},
/**
* Formating the columns selected
* @param {*} columns
* @returns
*/
formatColumnSelected(columns) {
let cols = _.clone(columns);
cols.pop();
return cols;
},
/**
* Event handler when update the settings columns
* @param {*} columns
*/
onUpdateColumnSettings(columns) {
let cols = columns;
if (_.findIndex(cols, 'actions') == -1) {
cols.push("actions");
}
this.columns = cols;
this.random = _.random(0, 10000000000);
}
}
}

View File

@@ -1,41 +1,51 @@
<template>
<div id="v-mycases" ref="v-mycases" class="v-container-mycases">
<b-alert
:show="dataAlert.dismissCountDown"
dismissible
:variant="dataAlert.variant"
@dismissed="dataAlert.dismissCountDown = 0"
@dismiss-count-down="countDownChanged"
>
{{ dataAlert.message }}
</b-alert>
<b-alert
:show="dataAlert.dismissCountDown"
dismissible
:variant="dataAlert.variant"
@dismissed="dataAlert.dismissCountDown = 0"
@dismiss-count-down="countDownChanged"
>
{{ dataAlert.message }}
</b-alert>
<button-fleft :data="newCase"></button-fleft>
<MyCasesFilter
:filters="filters"
:title="title"
:random="random"
:icon="filterHeaderObject.icon"
@onRemoveFilter="onRemoveFilter"
@onUpdateFilters="onUpdateFilters"
/>
<header-counter :data="headers"> </header-counter>
<modal-new-request ref="newRequest"></modal-new-request>
<settings-popover
:options="formatColumnSettings(options.headings)"
target="pm-dr-column-settings"
@onUpdateColumnSettings="onUpdateColumnSettings"
:key="random + 1"
:selected="formatColumnSelected(columns)"
/>
<v-server-table
:data="tableData"
:columns="columns"
:options="options"
ref="vueTable"
name="mycases"
@row-click="onRowClick"
:key="random"
>
<div slot="detail" slot-scope="props">
<div class="btn-default" @click="openCaseDetail(props.row)">
<i class="fas fa-info-circle"></i>
<i class="fas fa-info-circle"></i>
</div>
</div>
<div slot="case_number" slot-scope="props">
{{ props.row.CASE_NUMBER }}
</div>
<div slot="case_title" slot-scope="props">
{{ props.row.CASE_TITLE }}
<div slot="thread_title" slot-scope="props">
<ThreadTitleCell :data="props.row.THREAD_TITLE" />
</div>
<div slot="process_name" slot-scope="props">
{{ props.row.PROCESS_NAME }}
@@ -54,27 +64,38 @@
{{ props.row.DURATION }}
</div>
<div slot="actions" slot-scope="props">
<div class="btn-default" v-bind:style="{ color: props.row.MESSAGE_COLOR}" @click="openComments(props.row)">
<div
class="btn-default"
v-bind:style="{ color: props.row.MESSAGE_COLOR }"
@click="openComments(props.row)"
>
<span class="fas fa-comments"></span>
</div>
</div>
</v-server-table>
<ModalComments ref="modal-comments" @postNotes="onPostNotes"></ModalComments>
<ModalComments
ref="modal-comments"
@postNotes="onPostNotes"
></ModalComments>
</div>
</template>
<script>
import HeaderCounter from "../components/home/HeaderCounter.vue";
import ButtonFleft from "../components/home/ButtonFleft.vue";
import ModalNewRequest from "./ModalNewRequest.vue";
import MyCasesFilter from "../components/search/MyCasesFilter";
import ModalComments from "./modal/ModalComments.vue";
import GroupedCell from "../components/vuetable/GroupedCell.vue";
import api from "./../api/index";
import utils from "./../utils/utils";
import HeaderCounter from "../../components/home/HeaderCounter.vue";
import ButtonFleft from "../../components/home/ButtonFleft.vue";
import ModalNewRequest from "../ModalNewRequest.vue";
import MyCasesFilter from "../../components/search/MyCasesFilter";
import ModalComments from "../modal/ModalComments.vue";
import GroupedCell from "../../components/vuetable/GroupedCell.vue";
import ThreadTitleCell from "../../components/vuetable/ThreadTitleCell.vue"
import api from "../../api/index";
import utils from "../../utils/utils";
import defaultMixins from "./defaultMixins";
import { Event } from "vue-tables-2";
export default {
name: "MyCases",
mixins: [defaultMixins],
components: {
MyCasesFilter,
HeaderCounter,
@@ -82,22 +103,33 @@ export default {
ModalNewRequest,
GroupedCell,
ModalComments,
ThreadTitleCell,
},
props: ["filters", "defaultOption"],
props: ["defaultOption", "settings"],
data() {
let that = this;
return {
dataAlert: {
dismissSecs: 5,
dismissCountDown: 0,
message: "",
variant: "info"
dismissSecs: 5,
dismissCountDown: 0,
message: "",
variant: "info",
},
metrics: [],
title: this.$i18n.t('ID_MY_CASES'),
title: this.$i18n.t("ID_MY_CASES"),
filter: "CASES_INBOX",
allView: [],
filterHeader: "STARTED",
filterHeaderObject: {
icon:"fas fa-inbox"
},
headers: [],
columMap: {
case_number: "APP_NUMBER",
case_title: "DEL_TITLE",
process_name: "PRO_TITLE",
},
random: _.random(0,1000000000),
newCase: {
title: this.$i18n.t("ID_NEW_CASE"),
class: "btn-success",
@@ -105,24 +137,31 @@ export default {
this.$refs["newRequest"].show();
},
},
columns: [
"case_number",
"case_title",
"process_name",
"pending_taks",
"status",
"start_date",
"finish_date",
"duration",
"actions",
],
filters:
this.settings && this.settings.filters
? this.settings.filters
: {},
columns:
this.settings && this.settings.columns
? this.settings.columns
: [
"case_number",
"process_name",
"thread_title",
"pending_taks",
"status",
"start_date",
"finish_date",
"duration",
"actions",
],
tableData: [],
options: {
filterable: false,
headings: {
case_number: this.$i18n.t("ID_MYCASE_NUMBER"),
case_title: this.$i18n.t("ID_CASE_TITLE"),
process_name: this.$i18n.t("ID_PROCESS_NAME"),
thread_title: this.$i18n.t('ID_CASE_THREAD_TITLE'),
pending_taks: this.$i18n.t("ID_PENDING_TASKS"),
status: this.$i18n.t("ID_CASESLIST_APP_STATUS"),
start_date: this.$i18n.t("ID_START_DATE"),
@@ -131,13 +170,13 @@ export default {
actions: "",
},
texts: {
count:this.$i18n.t("ID_SHOWING_FROM_RECORDS_COUNT"),
count: this.$i18n.t("ID_SHOWING_FROM_RECORDS_COUNT"),
first: this.$i18n.t("ID_FIRST"),
last: this.$i18n.t("ID_LAST"),
filter: this.$i18n.t("ID_FILTER") + ":",
limit: this.$i18n.t("ID_RECORDS") + ":",
page: this.$i18n.t("ID_PAGE") + ":",
noResults: this.$i18n.t("ID_NO_MATCHING_RECORDS")
noResults: this.$i18n.t("ID_NO_MATCHING_RECORDS"),
},
selectable: {
mode: "single",
@@ -147,24 +186,44 @@ export default {
selectAllMode: "page",
programmatic: false,
},
sortable: ["case_number"],
orderBy:
this.settings && this.settings.orderBy
? this.settings.orderBy
: {},
requestFunction(data) {
return this.$parent.$parent.getCasesForVueTable(data);
},
settings: {
actions: {
class: "fas fa-cog",
id: "pm-dr-column-settings",
events: {
click() {
that.$root.$emit(
"bv::show::popover",
"pm-dr-column-settings"
);
},
},
},
},
},
translations: null,
pmDateFormat: window.config.FORMATS.dateFormat,
clickCount: 0,
singleClickTimer: null,
statusTitle: {
"ON_TIME": this.$i18n.t("ID_IN_PROGRESS"),
"OVERDUE": this.$i18n.t("ID_TASK_OVERDUE"),
"DRAFT": this.$i18n.t("ID_IN_DRAFT"),
"PAUSED": this.$i18n.t("ID_PAUSED"),
"UNASSIGNED": this.$i18n.t("ID_UNASSIGNED")
}
ON_TIME: this.$i18n.t("ID_IN_PROGRESS"),
OVERDUE: this.$i18n.t("ID_TASK_OVERDUE"),
DRAFT: this.$i18n.t("ID_IN_DRAFT"),
PAUSED: this.$i18n.t("ID_PAUSED"),
UNASSIGNED: this.$i18n.t("ID_UNASSIGNED"),
},
};
},
mounted() {
let that = this;
this.getHeaders();
this.openDefaultCase();
// force to open start cases modal
@@ -172,8 +231,37 @@ export default {
if (window.config._nodeId === "CASES_START_CASE") {
this.$refs["newRequest"].show();
}
// define sort event
Event.$on('vue-tables.mycases.sorted', function (data) {
that.$emit("updateSettings", {
data: data,
key: "orderBy",
parent: this.page,
type: "normal",
id: this.id
});
});
},
watch: {
columns: function (val) {
this.$emit("updateSettings", {
data: val,
key: "columns",
parent: this.page,
type: "normal",
id: this.id
});
},
filters: function (val) {
this.$emit("updateSettings", {
data: val,
key: "filters",
parent: this.page,
type: "normal",
id: this.id
});
},
},
watch: {},
computed: {
/**
* Build our ProcessMaker apiClient
@@ -190,12 +278,12 @@ export default {
*/
openDefaultCase() {
let params;
if(this.defaultOption) {
if (this.defaultOption) {
params = utils.getAllUrlParams(this.defaultOption);
if (params && params.app_uid && params.del_index) {
this.openCase({
APP_UID: params.app_uid,
DEL_INDEX: params.del_index
DEL_INDEX: params.del_index,
});
this.$emit("cleanDefaultOption");
}
@@ -210,7 +298,7 @@ export default {
self.clickCount += 1;
if (self.clickCount === 1) {
self.singleClickTimer = setTimeout(function() {
self.clickCount = 0;
self.clickCount = 0;
}, 400);
} else if (self.clickCount === 2) {
clearTimeout(self.singleClickTimer);
@@ -229,7 +317,7 @@ export default {
DEL_INDEX: item.DEL_INDEX,
PRO_UID: item.PRO_UID,
TAS_UID: item.TAS_UID,
ACTION: "todo"
ACTION: "todo",
});
this.$emit("onUpdatePage", "XCase");
},
@@ -241,17 +329,22 @@ export default {
openCaseDetail(item) {
let that = this;
api.cases.open(_.extend({ ACTION: "todo" }, item)).then(() => {
api.cases.cases_open(_.extend({ ACTION: "todo" }, item)).then(() => {
that.$emit("onUpdateDataCase", {
APP_UID: item.APP_UID,
DEL_INDEX: item.DEL_INDEX,
PRO_UID: item.PRO_UID,
TAS_UID: item.TAS_UID,
APP_NUMBER: item.CASE_NUMBER,
ACTION: that.filterHeader === "SUPERVISING" ? "to_revise": "todo"
api.cases
.cases_open(_.extend({ ACTION: "todo" }, item))
.then(() => {
that.$emit("onUpdateDataCase", {
APP_UID: item.APP_UID,
DEL_INDEX: item.DEL_INDEX,
PRO_UID: item.PRO_UID,
TAS_UID: item.TAS_UID,
APP_NUMBER: item.CASE_NUMBER,
ACTION:
that.filterHeader === "SUPERVISING"
? "to_revise"
: "todo",
});
that.$emit("onUpdatePage", "case-detail");
});
that.$emit("onUpdatePage", "case-detail");
});
});
},
/**
@@ -293,16 +386,22 @@ export default {
paged,
limit = data.limit,
start = data.page === 1 ? 0 : limit * (data.page - 1),
filters = {};
paged = start + "," + limit;
filters = {},
sort = "";
filters = {
filter: that.filterHeader,
paged: paged,
limit: limit,
offset: start
};
_.forIn(this.filters, function(item, key) {
filters[item.filterVar] = item.value;
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
.myCases(filters)
@@ -318,6 +417,20 @@ export default {
});
});
},
/**
* Prepare sort string to be sended in the service
* @param {object} data
* @returns {string}
*/
prepareSortString(data) {
let sort = "";
if (data.orderBy && this.columMap[data.orderBy]) {
sort = `${this.columMap[data.orderBy]},${
data.ascending === 1 ? "ASC" : "DESC"
}`;
}
return sort;
},
/**
* Format Response API TODO to grid inbox and columns
*/
@@ -327,18 +440,21 @@ export default {
_.forEach(response, (v) => {
data.push({
CASE_NUMBER: v.APP_NUMBER,
CASE_TITLE: v.DEL_TITLE,
THREAD_TITLE: v.THREAD_TITLES,
PROCESS_NAME: v.PRO_TITLE,
STATUS: v.APP_STATUS,
START_DATE: v.APP_CREATE_DATE_LABEL || "",
FINISH_DATE: v.APP_FINISH_DATE_LABEL || "",
PENDING_TASKS: that.formantPendingTask(v.PENDING, v.APP_STATUS),
PENDING_TASKS: that.formantPendingTask(
v.PENDING,
v.APP_STATUS
),
DURATION: v.DURATION,
DEL_INDEX: v.DEL_INDEX,
APP_UID: v.APP_UID,
PRO_UID: v.PRO_UID,
TAS_UID: v.TAS_UID,
MESSAGE_COLOR: v.CASE_NOTES_COUNT > 0 ? "black":"silver"
MESSAGE_COLOR: v.CASE_NOTES_COUNT > 0 ? "black" : "silver",
});
});
return data;
@@ -352,26 +468,34 @@ export default {
dataFormat = [];
for (i = 0; i < data.length; i += 1) {
userDataFormat = utils.userNameDisplayFormat({
userName: data[i].user_tooltip.usr_username || "",
firstName: data[i].user_tooltip.usr_firstname || "",
lastName: data[i].user_tooltip.usr_lastname || "",
format: window.config.FORMATS.format || null
});
dataFormat.push(
{
TAS_NAME: data[i].tas_title,
STATUS: data[i].tas_color,
DELAYED_TITLE: this.delayedTitle(data[i], status),
DELAYED_MSG: data[i].tas_status === "OVERDUE" && status !== "COMPLETED" ? data[i].delay : "",
AVATAR: userDataFormat !== "" ? window.config.SYS_SERVER_AJAX +
window.config.SYS_URI +
`users/users_ViewPhotoGrid?pUID=${data[i].user_id}` : "",
USERNAME: userDataFormat !== "" ? userDataFormat : this.$i18n.t("ID_UNASSIGNED"),
POSITION: data[i].user_tooltip.usr_position,
EMAIL: data[i].user_tooltip.usr_email,
UNASSIGNED: userDataFormat !== "" ? true : false
}
);
userName: data[i].user_tooltip.usr_username || "",
firstName: data[i].user_tooltip.usr_firstname || "",
lastName: data[i].user_tooltip.usr_lastname || "",
format: window.config.FORMATS.format || null,
});
dataFormat.push({
TAS_NAME: data[i].tas_title,
STATUS: data[i].tas_color,
DELAYED_TITLE: this.delayedTitle(data[i], status),
DELAYED_MSG:
data[i].tas_status === "OVERDUE" &&
status !== "COMPLETED"
? data[i].delay
: "",
AVATAR:
userDataFormat !== ""
? window.config.SYS_SERVER_AJAX +
window.config.SYS_URI +
`users/users_ViewPhotoGrid?pUID=${data[i].user_id}`
: "",
USERNAME:
userDataFormat !== ""
? userDataFormat
: this.$i18n.t("ID_UNASSIGNED"),
POSITION: data[i].user_tooltip.usr_position,
EMAIL: data[i].user_tooltip.usr_email,
UNASSIGNED: userDataFormat !== "" ? true : false,
});
}
return dataFormat;
},
@@ -379,16 +503,21 @@ export default {
* Prepare the delayed title
* @param {object} data
* @param {string} status
* @returns {string}
* @returns {string}
*/
delayedTitle(data, status) {
let title = "";
if (status === "COMPLETED") {
title = this.$i18n.t("ID_COMPLETED") + ": ";
title += data.tas_status === "ON_TIME" ? this.$i18n.t("ID_ON_TIME"): this.$i18n.t("ID_TASK_OVERDUE");
title +=
data.tas_status === "ON_TIME"
? this.$i18n.t("ID_ON_TIME")
: this.$i18n.t("ID_TASK_OVERDUE");
} else {
title = data.tas_status === "OVERDUE" ?
this.$i18n.t("ID_DELAYED") + ":" : this.statusTitle[data.tas_status];
title =
data.tas_status === "OVERDUE"
? this.$i18n.t("ID_DELAYED") + ":"
: this.statusTitle[data.tas_status];
}
return title;
},
@@ -505,7 +634,7 @@ export default {
};
_.forEach(response, (v) => {
//Hack for display the SUPERVISING CARD
if(!(v.id === "SUPERVISING" && v.counter === 0)){
if (!(v.id === "SUPERVISING" && v.counter === 0)) {
data.push({
title: v.title,
counter: v.counter,
@@ -516,8 +645,10 @@ export default {
that.filterHeader = obj.item;
that.$refs["vueTable"].setPage(1); // Reset the page when change the header filter
that.$refs["vueTable"].getData();
that.filterHeaderObject = obj;
that.random = _.random(0,1000000000);
},
class: info[v.id].class
class: info[v.id].class,
});
}
});
@@ -534,10 +665,9 @@ export default {
that.$refs["modal-comments"].show();
});
},
onRemoveFilter(data) {
},
onRemoveFilter(data) {},
onUpdateFilters(data) {
this.$emit("onUpdateFilters", data.params);
this.filters = data.params;
if (data.refresh) {
this.$nextTick(() => {
this.$refs["vueTable"].getData();
@@ -556,9 +686,9 @@ export default {
* @param {string} type - alert type
*/
showAlert(message, type) {
this.dataAlert.message = message;
this.dataAlert.variant = type || "info";
this.dataAlert.dismissCountDown = this.dataAlert.dismissSecs;
this.dataAlert.message = message;
this.dataAlert.variant = type || "info";
this.dataAlert.dismissCountDown = this.dataAlert.dismissSecs;
},
/**
* Updates the alert dismiss value to update
@@ -566,7 +696,7 @@ export default {
* @param {mumber}
*/
countDownChanged(dismissCountDown) {
this.dataAlert.dismissCountDown = dismissCountDown;
this.dataAlert.dismissCountDown = dismissCountDown;
},
},
};
@@ -578,4 +708,4 @@ export default {
padding-left: 50px;
padding-right: 50px;
}
</style>
</style>

View File

@@ -0,0 +1,46 @@
import api from "../../api/index";
export default {
data() {
return {
random: 1
};
},
methods: {
/**
* Format columns for custom columns
* @param {*} headings
* @returns
*/
formatColumnSettings(headings) {
let res = [];
_.forEach(headings, function (value, key) {
if (key != "actions") {
res.push({ value, key });
}
});
return res;
},
/**
* Formating the columns selected
* @param {*} columns
* @returns
*/
formatColumnSelected(columns) {
let cols = _.clone(columns);
cols.pop();
return cols;
},
/**
* Event handler when update the settings columns
* @param {*} columns
*/
onUpdateColumnSettings(columns) {
let cols = columns;
if (_.findIndex(cols, 'actions') == -1) {
cols.push("actions");
}
this.columns = cols;
this.random = _.random(0, 10000000000);
}
}
}

View File

@@ -1,371 +0,0 @@
<template>
<div id="v-paused" ref="v-paused" class="v-container-paused">
<button-fleft :data="newCase"></button-fleft>
<modal-new-request ref="newRequest"></modal-new-request>
<CasesFilter
:filters="filters"
:title="$t('ID_PAUSED')"
@onRemoveFilter="onRemoveFilter"
@onUpdateFilters="onUpdateFilters"
/>
<v-server-table
:data="tableData"
:columns="columns"
:options="options"
ref="vueTable"
@row-click="onRowClick"
>
<div slot="detail" slot-scope="props">
<div class="btn-default" @click="openCaseDetail(props.row)">
<i class="fas fa-info-circle"></i>
</div>
</div>
<div slot="case_number" slot-scope="props">
{{ props.row.CASE_NUMBER }}
</div>
<div slot="case_title" slot-scope="props">
{{ props.row.CASE_TITLE }}
</div>
<div slot="process_name" slot-scope="props">
{{ props.row.PROCESS_NAME }}
</div>
<div slot="task" slot-scope="props">
<TaskCell :data="props.row.TASK" />
</div>
<div slot="current_user" slot-scope="props">
{{ props.row.USERNAME_DISPLAY_FORMAT }}
</div>
<div slot="due_date" slot-scope="props">
{{ props.row.DUE_DATE }}
</div>
<div slot="delegation_date" slot-scope="props">
{{ props.row.DELEGATION_DATE }}
</div>
<div slot="priority" slot-scope="props">{{ props.row.PRIORITY }}</div>
<div slot="actions" slot-scope="props">
<button
class="btn btn-success btn-sm"
@click="showModalUnpauseCase(props.row)"
>
{{ $t("ID_UNPAUSE") }}
</button>
</div>
</v-server-table>
<ModalUnpauseCase ref="modal-unpause-case"></ModalUnpauseCase>
</div>
</template>
<script>
import HeaderCounter from "../components/home/HeaderCounter.vue";
import ButtonFleft from "../components/home/ButtonFleft.vue";
import ModalNewRequest from "./ModalNewRequest.vue";
import CasesFilter from "../components/search/CasesFilter";
import TaskCell from "../components/vuetable/TaskCell.vue";
import ModalUnpauseCase from "./modal/ModalUnpauseCase.vue";
import api from "./../api/index";
import utils from "./../utils/utils";
export default {
name: "Paused",
components: {
HeaderCounter,
ButtonFleft,
ModalNewRequest,
TaskCell,
ModalUnpauseCase,
CasesFilter,
},
props: ["defaultOption", "filters"],
data() {
return {
newCase: {
title: this.$i18n.t("ID_NEW_CASE"),
class: "btn-success",
onClick: () => {
this.$refs["newRequest"].show();
},
},
columns: [
"detail",
"case_number",
"case_title",
"process_name",
"task",
"due_date",
"delegation_date",
"priority",
"actions",
],
tableData: [],
options: {
filterable: false,
headings: {
case_number: this.$i18n.t("ID_MYCASE_NUMBER"),
case_title: this.$i18n.t("ID_CASE_TITLE"),
process_name: this.$i18n.t("ID_PROCESS_NAME"),
task: this.$i18n.t("ID_TASK"),
current_user: this.$i18n.t("ID_CURRENT_USER"),
due_date: this.$i18n.t("ID_DUE_DATE"),
delegation_date: this.$i18n.t("ID_DELEGATION_DATE"),
priority: this.$i18n.t("ID_PRIORITY"),
actions: "",
detail: "",
},
texts: {
count:this.$i18n.t("ID_SHOWING_FROM_RECORDS_COUNT"),
first: this.$i18n.t("ID_FIRST"),
last: this.$i18n.t("ID_LAST"),
filter: this.$i18n.t("ID_FILTER") + ":",
limit: this.$i18n.t("ID_RECORDS") + ":",
page: this.$i18n.t("ID_PAGE") + ":",
noResults: this.$i18n.t("ID_NO_MATCHING_RECORDS")
},
selectable: {
mode: "single",
only: function (row) {
return true;
},
selectAllMode: "page",
programmatic: false,
},
requestFunction(data) {
return this.$parent.$parent.getCasesForVueTable(data);
},
},
pmDateFormat: "Y-m-d H:i:s",
clickCount: 0,
singleClickTimer: null,
statusTitle: {
"ON_TIME": this.$i18n.t("ID_IN_PROGRESS"),
"OVERDUE": this.$i18n.t("ID_TASK_OVERDUE"),
"DRAFT": this.$i18n.t("ID_IN_DRAFT"),
"PAUSED": this.$i18n.t("ID_PAUSED"),
"UNASSIGNED": this.$i18n.t("ID_UNASSIGNED")
}
};
},
created() {
this.initFilters();
},
mounted() {
// force to open case
this.openDefaultCase();
},
watch: {},
computed: {
/**
* Build our ProcessMaker apiClient
*/
ProcessMaker() {
return window.ProcessMaker;
},
},
updated() {},
beforeCreate() {},
methods: {
/**
* Initialize filters
*/
initFilters() {
let params;
if(this.defaultOption) {
params = utils.getAllUrlParams(this.defaultOption);
if (params && params.openapplicationuid) {
this.$emit("onUpdateFilters",[
{
fieldId: "caseNumber",
filterVar: "caseNumber",
label: "",
options:[],
value: params.openapplicationuid,
autoShow: false
}
]);
}
}
},
/**
* Open a case when the component was mounted
*/
openDefaultCase() {
let params;
if(this.defaultOption) {
params = utils.getAllUrlParams(this.defaultOption);
if (params && params.app_uid && params.del_index) {
this.openCase({
APP_UID: params.app_uid,
DEL_INDEX: params.del_index
});
this.$emit("cleanDefaultOption");
}
//force to search in the parallel tasks
if (params && params.openapplicationuid) {
this.onUpdateFilters({
params: [
{
fieldId: "caseNumber",
filterVar: "caseNumber",
label: "",
options:[],
value: params.openapplicationuid,
autoShow: false
}
],
refresh: false
});
this.$emit("cleanDefaultOption");
}
}
},
/**
* On row click event handler
* @param {object} event
*/
onRowClick(event) {
let self = this;
self.clickCount += 1;
if (self.clickCount === 1) {
self.singleClickTimer = setTimeout(function() {
self.clickCount = 0;
}, 400);
} else if (self.clickCount === 2) {
clearTimeout(self.singleClickTimer);
self.clickCount = 0;
self.showModalUnpauseCase(event.row);
}
},
/**
* Get cases todo data
*/
getCasesForVueTable(data) {
let that = this,
dt,
paged,
limit = data.limit,
start = data.page === 1 ? 0 : limit * (data.page - 1),
filters = {};
paged = start + "," + limit;
filters = {
paged: paged,
};
_.forIn(this.filters, function (item, key) {
filters[item.filterVar] = item.value;
});
return new Promise((resolutionFunc, rejectionFunc) => {
api.cases
.paused(filters)
.then((response) => {
dt = that.formatDataResponse(response.data.data);
resolutionFunc({
data: dt,
count: response.data.total,
});
})
.catch((e) => {
rejectionFunc(e);
});
});
},
/**
* Format Response API TODO to grid todo and columns
*/
formatDataResponse(response) {
let data = [];
_.forEach(response, (v) => {
data.push({
CASE_NUMBER: v.APP_NUMBER,
CASE_TITLE: v.DEL_TITLE,
PROCESS_NAME: v.PRO_TITLE,
TASK: [{
TITLE: v.TAS_TITLE,
CODE_COLOR: v.TAS_COLOR,
COLOR: v.TAS_COLOR_LABEL,
DELAYED_TITLE: v.TAS_STATUS === "OVERDUE" ?
this.$i18n.t("ID_DELAYED") + ":" : this.statusTitle[v.TAS_STATUS],
DELAYED_MSG: v.TAS_STATUS === "OVERDUE" ? v.DELAY : ""
}],
USERNAME_DISPLAY_FORMAT: utils.userNameDisplayFormat({
userName: v.USR_LASTNAME,
firstName: v.USR_LASTNAME,
lastName: v.USR_LASTNAME,
format: window.config.FORMATS.format || null
}),
DUE_DATE: v.DEL_TASK_DUE_DATE_LABEL,
DELEGATION_DATE: v.DEL_DELEGATE_DATE_LABEL,
PRIORITY: v.DEL_PRIORITY_LABEL,
DEL_INDEX: v.DEL_INDEX,
APP_UID: v.APP_UID,
PRO_UID: v.PRO_UID,
TAS_UID: v.TAS_UID,
});
});
return data;
},
/**
* Open selected cases in the inbox
*
* @param {object} item
*/
openCase(item) {
this.$emit("onUpdateDataCase", {
APP_UID: item.APP_UID,
DEL_INDEX: item.DEL_INDEX,
PRO_UID: item.PRO_UID,
TAS_UID: item.TAS_UID,
ACTION: "todo"
});
this.$emit("onUpdatePage", "XCase");
},
/**
* Open case detail
*
* @param {object} item
*/
openCaseDetail(item) {
let that = this;
api.cases.open(_.extend({ ACTION: "todo" }, item)).then(() => {
api.cases.cases_open(_.extend({ ACTION: "todo" }, item)).then(() => {
that.$emit("onUpdateDataCase", {
APP_UID: item.APP_UID,
DEL_INDEX: item.DEL_INDEX,
PRO_UID: item.PRO_UID,
TAS_UID: item.TAS_UID,
APP_NUMBER: item.CASE_NUMBER,
});
that.$emit("onUpdatePage", "case-detail");
});
});
},
showModalUnpauseCase(item) {
this.$refs["modal-unpause-case"].data = item;
this.$refs["modal-unpause-case"].show();
},
onRemoveFilter(data) {},
onUpdateFilters(data) {
this.$emit("onUpdateFilters", data.params);
if (data.refresh) {
this.$nextTick(() => {
this.$refs["vueTable"].getData();
});
}
},
/**
* update view in component
*/
updateView(){
this.$refs["vueTable"].getData();
}
},
};
</script>
<style>
.v-container-paused {
padding-top: 20px;
padding-bottom: 20px;
padding-left: 50px;
padding-right: 50px;
}
</style>

View File

@@ -0,0 +1,705 @@
<template>
<div id="v-paused" ref="v-paused" class="v-container-paused">
<button-fleft :data="newCase"></button-fleft>
<modal-new-request ref="newRequest"></modal-new-request>
<ModalReassignCase ref="modal-reassign-case"></ModalReassignCase>
<CasesFilter
:filters="filters"
:title="$t('ID_PAUSED')"
:icon="icon"
@onRemoveFilter="onRemoveFilter"
@onUpdateFilters="onUpdateFilters"
/>
<multiview-header
:data="dataMultiviewHeader"
:dataSubtitle="dataSubtitle"
/>
<settings-popover :options="formatColumnSettings(options.headings)" target="pm-dr-column-settings" @onUpdateColumnSettings="onUpdateColumnSettings" :key="random+1" :selected="formatColumnSelected(columns)"/>
<v-server-table
v-if="typeView === 'GRID'"
:data="tableData"
:columns="columns"
:options="options"
ref="vueTable"
@row-click="onRowClick"
:key="random"
name="paused"
>
<div slot="detail" slot-scope="props">
<div class="btn-default" @click="openCaseDetail(props.row)">
<i class="fas fa-info-circle"></i>
</div>
</div>
<div slot="case_number" slot-scope="props">
{{ props.row.CASE_NUMBER }}
</div>
<div slot="case_title" slot-scope="props">
{{ props.row.CASE_TITLE }}
</div>
<div slot="process_name" slot-scope="props">
{{ props.row.PROCESS_NAME }}
</div>
<div slot="task" slot-scope="props">
<TaskCell :data="props.row.TASK" />
</div>
<div slot="send_by" slot-scope="props">
<CurrentUserCell :data="props.row.USER_DATA" />
</div>
<div slot="current_user" slot-scope="props">
{{ props.row.USERNAME_DISPLAY_FORMAT }}
</div>
<div slot="due_date" slot-scope="props">
{{ props.row.DUE_DATE }}
</div>
<div slot="delegation_date" slot-scope="props">
{{ props.row.DELEGATION_DATE }}
</div>
<div slot="priority" slot-scope="props">{{ props.row.PRIORITY }}</div>
<div slot="actions" slot-scope="props">
<div @click="updateDataEllipsis(props.row)">
<ellipsis :ref="`ellipsis-${props.row.TAS_UID}`" v-if="dataEllipsis" :data="dataEllipsis"> </ellipsis>
</div>
</div>
</v-server-table>
<VueCardView
v-if="typeView === 'CARD'"
:options="optionsVueView"
ref="vueCardView"
>
<div slot="actions" slot-scope="props">
<b-row>
<b-col sm="12">
<div class="v-pm-card-info" @click="openCaseDetail(props.item)">
<i class="fas fa-info-circle"></i>
</div>
</b-col>
<b-col sm="12">
<div class="ellipsis-container" @click="updateDataEllipsis(props.item)">
<ellipsis :ref="`ellipsis-${props.item.TAS_UID}`" v-if="dataEllipsis" :data="dataEllipsis"> </ellipsis>
</div>
</b-col>
</b-row>
</div>
<div slot="case_number" slot-scope="props" class="v-card-text">
<span class="v-card-text-highlight"
>{{ props["headings"][props.column] }} : {{ props["item"]["CASE_NUMBER"] }}</span
>
</div>
<div slot="case_title" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light"
>{{ props["item"]["CASE_TITLE"] }}
</span>
</div>
<div slot="process_name" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light"
>{{ props["item"]["PROCESS_NAME"] }}
</span>
</div>
<div slot="due_date" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light"
>{{ props["item"]["DUE_DATE"] }}
</span>
</div>
<div slot="delegation_date" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light"
>{{ props["item"]["DELEGATION_DATE"] }}
</span>
</div>
<div slot="task" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light">
<TaskCell :data="props.item.TASK" />
</span>
</div>
<div slot="send_by" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light">
<CurrentUserCell :data="props.item.USER_DATA" />
</span>
</div>
</VueCardView>
<VueListView
v-if="typeView === 'LIST'"
:options="optionsVueView"
ref="vueListView"
>
<div slot="actions" slot-scope="props">
<b-row>
<b-col sm="12">
<div class="v-pm-card-info" @click="openCaseDetail(props.item)">
<i class="fas fa-info-circle"></i>
</div>
</b-col>
<b-col sm="12">
<div class="ellipsis-container" @click="updateDataEllipsis(props.item)">
<ellipsis :ref="`ellipsis-${props.item.TAS_UID}`" v-if="dataEllipsis" :data="dataEllipsis"> </ellipsis>
</div>
</b-col>
</b-row>
</div>
<div slot="case_number" slot-scope="props" class="v-card-text">
<span class="v-card-text-highlight"
>{{ props["headings"][props.column] }} : {{ props["item"]["CASE_NUMBER"] }}</span
>
</div>
<div slot="case_title" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light"
>{{ props["item"]["CASE_TITLE"] }}
</span>
</div>
<div slot="process_name" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light"
>{{ props["item"]["PROCESS_NAME"] }}
</span>
</div>
<div slot="due_date" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light"
>{{ props["item"]["DUE_DATE"] }}
</span>
</div>
<div slot="delegation_date" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light"
>{{ props["item"]["DELEGATION_DATE"] }}
</span>
</div>
<div slot="task" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light">
<TaskCell :data="props.item.TASK" />
</span>
</div>
<div slot="send_by" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light">
<CurrentUserCell :data="props.item.USER_DATA" />
</span>
</div>
</VueListView>
<ModalUnpauseCase ref="modal-unpause-case"></ModalUnpauseCase>
</div>
</template>
<script>
import HeaderCounter from "../../components/home/HeaderCounter.vue";
import ButtonFleft from "../../components/home/ButtonFleft.vue";
import ModalNewRequest from "../ModalNewRequest.vue";
import CasesFilter from "../../components/search/CasesFilter";
import TaskCell from "../../components/vuetable/TaskCell.vue";
import ModalUnpauseCase from "../modal/ModalUnpauseCase.vue";
import api from "../../api/index";
import utils from "../../utils/utils";
import MultiviewHeader from "../../components/headers/MultiviewHeader.vue";
import VueCardView from "../../components/dataViews/vueCardView/VueCardView.vue";
import VueListView from "../../components/dataViews/vueListView/VueListView.vue";
import defaultMixins from "./defaultMixins";
import Ellipsis from '../../components/utils/ellipsis.vue';
import ModalReassignCase from '../modal/ModalReassignCase.vue';
import { Event } from 'vue-tables-2';
import CurrentUserCell from "../../components/vuetable/CurrentUserCell.vue";
export default {
name: "Paused",
mixins: [defaultMixins],
components: {
HeaderCounter,
ButtonFleft,
ModalNewRequest,
TaskCell,
ModalUnpauseCase,
CasesFilter,
Ellipsis,
MultiviewHeader,
VueCardView,
VueListView,
ModalReassignCase,
CurrentUserCell,
},
props: ["defaultOption", "settings"],
data() {
let that = this;
return {
columMap: {
case_number: "APP_NUMBER",
case_title: "DEL_TITLE",
process_name: "PRO_TITLE"
},
newCase: {
title: this.$i18n.t("ID_NEW_CASE"),
class: "btn-success",
onClick: () => {
this.$refs["newRequest"].show();
},
},
filters:
this.settings && this.settings.filters
? this.settings.filters
: {},
columns:
this.settings && this.settings.columns
? this.settings.columns
: [
"detail",
"case_number",
"case_title",
"process_name",
"task",
"send_by",
"due_date",
"delegation_date",
"priority",
"actions"
],
tableData: [],
icon:"far fa-pause-circle",
options: {
filterable: false,
headings: {
detail: this.$i18n.t("ID_DETAIL_CASE"),
case_number: this.$i18n.t("ID_MYCASE_NUMBER"),
case_title: this.$i18n.t("ID_CASE_TITLE"),
process_name: this.$i18n.t("ID_PROCESS_NAME"),
task: this.$i18n.t("ID_TASK"),
send_by: this.$i18n.t("ID_SEND_BY"),
due_date: this.$i18n.t("ID_DUE_DATE"),
delegation_date: this.$i18n.t("ID_DELEGATION_DATE"),
priority: this.$i18n.t("ID_PRIORITY"),
actions: ""
},
texts: {
count:this.$i18n.t("ID_SHOWING_FROM_RECORDS_COUNT"),
first: this.$i18n.t("ID_FIRST"),
last: this.$i18n.t("ID_LAST"),
filter: this.$i18n.t("ID_FILTER") + ":",
limit: this.$i18n.t("ID_RECORDS") + ":",
page: this.$i18n.t("ID_PAGE") + ":",
noResults: this.$i18n.t("ID_NO_MATCHING_RECORDS")
},
selectable: {
mode: "single",
only: function (row) {
return true;
},
selectAllMode: "page",
programmatic: false,
},
sortable: ['case_number'],
orderBy: this.settings && this.settings.orderBy ? this.settings.orderBy: {},
requestFunction(data) {
return this.$parent.$parent.getCasesForVueTable(data);
},
settings: {
"actions":{
class: "fas fa-cog",
id:"pm-dr-column-settings",
events:{
click(){
that.$root.$emit('bv::show::popover', 'pm-dr-column-settings')
}
}
}
},
},
pmDateFormat: "Y-m-d H:i:s",
clickCount: 0,
singleClickTimer: null,
statusTitle: {
"ON_TIME": this.$i18n.t("ID_IN_PROGRESS"),
"OVERDUE": this.$i18n.t("ID_TASK_OVERDUE"),
"DRAFT": this.$i18n.t("ID_IN_DRAFT"),
"PAUSED": this.$i18n.t("ID_PAUSED"),
"UNASSIGNED": this.$i18n.t("ID_UNASSIGNED")
},
dataEllipsis: {
buttons: {}
},
showEllipsis: false,
dataSubtitle: null
};
},
created() {
this.initFilters();
},
mounted() {
let that = this;
// force to open case
this.openDefaultCase();
Event.$on('vue-tables.paused.sorted', function (data) {
that.$emit("updateSettings", {
data: data,
key: "orderBy",
parent: this.page,
type: "normal",
id: this.id
});
});
},
watch: {
columns: function (val) {
this.$emit("updateSettings", {
data: val,
key: "columns",
parent: this.page,
type: "normal",
id: this.id
});
},
filters: function (val) {
this.$emit("updateSettings", {
data: val,
key: "filters",
parent: this.page,
type: "normal",
id: this.id
});
},
},
computed: {
/**
* Build our ProcessMaker apiClient
*/
ProcessMaker() {
return window.ProcessMaker;
},
},
updated() {},
beforeCreate() {},
methods: {
/**
* Initialize filters
*/
initFilters() {
let params;
if(this.defaultOption) {
params = utils.getAllUrlParams(this.defaultOption);
if (params && params.openapplicationuid) {
this.$emit("onUpdateFilters",[
{
fieldId: "caseNumber",
filterVar: "caseNumber",
label: "",
options:[],
value: params.openapplicationuid,
autoShow: false
}
]);
}
}
},
/**
* Open a case when the component was mounted
*/
openDefaultCase() {
let params;
if(this.defaultOption) {
params = utils.getAllUrlParams(this.defaultOption);
if (params && params.app_uid && params.del_index) {
this.openCase({
APP_UID: params.app_uid,
DEL_INDEX: params.del_index
});
this.$emit("cleanDefaultOption");
}
//force to search in the parallel tasks
if (params && params.openapplicationuid) {
this.onUpdateFilters({
params: [
{
fieldId: "caseNumber",
filterVar: "caseNumber",
label: "",
options:[],
value: params.openapplicationuid,
autoShow: false
}
],
refresh: false
});
this.$emit("cleanDefaultOption");
}
}
},
/**
* On row click event handler
* @param {object} event
*/
onRowClick(event) {
let self = this;
self.clickCount += 1;
if (self.clickCount === 1) {
self.singleClickTimer = setTimeout(function() {
self.clickCount = 0;
}, 400);
} else if (self.clickCount === 2) {
clearTimeout(self.singleClickTimer);
self.clickCount = 0;
self.showModalUnpauseCase(event.row);
}
},
/**
* Get cases todo data
*/
getCasesForVueTable(data) {
let that = this,
dt,
paged,
limit = data.limit,
start = data.page === 1 ? 0 : limit * (data.page - 1),
filters = {},
sort = "";
filters = {
limit: limit,
offset: start
};
_.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
.paused(filters)
.then((response) => {
dt = that.formatDataResponse(response.data.data);
resolutionFunc({
data: dt,
count: response.data.total,
});
})
.catch((e) => {
rejectionFunc(e);
});
});
},
/**
* Prepare sort string to be sended in the service
* @param {object} data
* @returns {string}
*/
prepareSortString(data){
let sort = "";
if (data.orderBy && this.columMap[data.orderBy]) {
sort = `${this.columMap[data.orderBy]},${data.ascending === 1 ? "ASC": "DESC"}`;
}
return sort;
},
/**
* Format Response API TODO to grid todo and columns
*/
formatDataResponse(response) {
let data = [];
_.forEach(response, (v) => {
data.push({
CASE_NUMBER: v.APP_NUMBER,
CASE_TITLE: v.DEL_TITLE,
PROCESS_NAME: v.PRO_TITLE,
TASK: [{
TITLE: v.TAS_TITLE,
CODE_COLOR: v.TAS_COLOR,
COLOR: v.TAS_COLOR_LABEL,
DELAYED_TITLE: v.TAS_STATUS === "OVERDUE" ?
this.$i18n.t("ID_DELAYED") + ":" : this.statusTitle[v.TAS_STATUS],
DELAYED_MSG: v.TAS_STATUS === "OVERDUE" ? v.DELAY : ""
}],
USER_DATA: this.formatUser(v.SEND_BY_INFO),
USERNAME_DISPLAY_FORMAT: utils.userNameDisplayFormat({
userName: v.USR_LASTNAME,
firstName: v.USR_LASTNAME,
lastName: v.USR_LASTNAME,
format: window.config.FORMATS.format || null
}),
DUE_DATE: v.DEL_TASK_DUE_DATE_LABEL,
DELEGATION_DATE: v.DEL_DELEGATE_DATE_LABEL,
PRIORITY: v.DEL_PRIORITY_LABEL,
DEL_INDEX: v.DEL_INDEX,
APP_UID: v.APP_UID,
PRO_UID: v.PRO_UID,
TAS_UID: v.TAS_UID,
});
});
return data;
},
/**
* Set the format to show user's information
* @return {array} dataFormat
*/
formatUser(data) {
var dataFormat = [],
userDataFormat;
userDataFormat = utils.userNameDisplayFormat({
userName: data.user_tooltip.usr_firstname,
firstName: data.user_tooltip.usr_lastname,
lastName: data.user_tooltip.usr_username,
format: window.config.FORMATS.format || null
});
dataFormat.push({
USERNAME_DISPLAY_FORMAT: userDataFormat,
EMAIL: data.user_tooltip.usr_email,
POSITION: data.user_tooltip.usr_position,
AVATAR: userDataFormat !== "" ? window.config.SYS_SERVER_AJAX +
window.config.SYS_URI +
`users/users_ViewPhotoGrid?pUID=${data.user_tooltip.usr_id}` : "",
UNASSIGNED: userDataFormat !== "" ? true : false
});
return dataFormat;
},
/**
* Open selected cases in the inbox
*
* @param {object} item
*/
openCase(item) {
this.$emit("onUpdateDataCase", {
APP_UID: item.APP_UID,
DEL_INDEX: item.DEL_INDEX,
PRO_UID: item.PRO_UID,
TAS_UID: item.TAS_UID,
ACTION: "todo"
});
this.$emit("onUpdatePage", "XCase");
},
/**
* Open case detail
*
* @param {object} item
*/
openCaseDetail(item) {
let that = this;
api.cases.open(_.extend({ ACTION: "todo" }, item)).then(() => {
api.cases.cases_open(_.extend({ ACTION: "todo" }, item)).then(() => {
that.$emit("onUpdateDataCase", {
APP_UID: item.APP_UID,
DEL_INDEX: item.DEL_INDEX,
PRO_UID: item.PRO_UID,
TAS_UID: item.TAS_UID,
APP_NUMBER: item.CASE_NUMBER,
});
that.$emit("onUpdatePage", "case-detail");
});
});
},
showModalUnpauseCase(item) {
this.$refs["modal-unpause-case"].data = item;
this.$refs["modal-unpause-case"].show();
},
onRemoveFilter(data) {},
onUpdateFilters(data) {
this.filters = data.params;
if (data.refresh) {
this.$nextTick(() => {
if (this.typeView === "GRID") {
this.$refs["vueTable"].getData();
}
if (this.typeView === "CARD") {
this.$refs["vueCardView"].getData();
}
if (this.typeView === "LIST") {
this.$refs["vueListView"].getData();
}
});
}
},
/**
* update view in component
*/
updateView(){
if (this.typeView === "GRID") {
this.$refs["vueTable"].getData();
}
if (this.typeView === "CARD") {
this.$refs["vueCardView"].getData();
}
if (this.typeView === "LIST") {
this.$refs["vueListView"].getData();
}
},
/**
* Show modal to reassign a case
* @param {object} data
*/
showModalReassign(data) {
this.$refs["modal-reassign-case"].data = data;
this.$refs["modal-reassign-case"].show();
},
/**
* Show options in the ellipsis
* @param {object} data
*/
updateDataEllipsis(data) {
let that = this;
this.showEllipsis = !this.showEllipsis;
if (this.showEllipsis) {
this.dataEllipsis = {
buttons: {
note: {
name: "case note",
icon: "far fa-comments",
fn: function() {
that.openCaseDetail(data);
}
},
play: {
name: "play case",
icon: "far fa-play-circle",
fn: function() {
that.showModalUnpauseCase(data);
}
},
reassign: {
name: "reassign case",
icon: "fas fa-undo",
fn: function() {
that.showModalReassign(data);
}
}
}
}
}
},
},
};
</script>
<style>
.v-container-paused {
padding-top: 20px;
padding-bottom: 20px;
padding-left: 50px;
padding-right: 50px;
}
</style>

View File

@@ -0,0 +1,171 @@
import api from "../../api/index";
export default {
data() {
let that = this;
return {
typeView: "GRID",
random: 1,
dataMultiviewHeader: {
actions: [
{
id: "view-grid",
title: "Grid",
onClick(action) {
that.typeView = "GRID";
},
icon: "fas fa-table",
},
{
id: "view-list",
title: "List",
onClick(action) {
that.typeView = "LIST";
},
icon: "fas fa-list",
},
{
id: "view-card",
title: "Card",
onClick(action) {
that.typeView = "CARD";
},
icon: "fas fa-th",
},
],
},
optionsVueView: {
limit: 10,
dblClick:(event, item, options)=>{
this.openCase(item);
},
headings: {
case_number: this.$i18n.t("ID_MYCASE_NUMBER"),
case_title: this.$i18n.t("ID_CASE_TITLE"),
process_name: this.$i18n.t("ID_PROCESS_NAME"),
task: this.$i18n.t("ID_TASK"),
send_by: this.$i18n.t("ID_SEND_BY"),
current_user: this.$i18n.t("ID_CURRENT_USER"),
due_date: this.$i18n.t("ID_DUE_DATE"),
delegation_date: this.$i18n.t("ID_DELEGATION_DATE"),
priority: this.$i18n.t("ID_PRIORITY")
},
columns: [
"case_number",
"case_title",
"process_name",
"due_date",
"delegation_date",
"priority",
"task",
"send_by",
],
requestFunction(data) {
return that.getCases(data);
},
requestFunctionViewMore(data) {
return that.getCasesViewMore(data);
}
}
}
},
created: function () {
},
methods: {
/**
* Get cases for Vue Card View
*/
getCases(data) {
let that = this,
dt,
filters = {};
_.forIn(this.filters, function (item, key) {
filters[item.filterVar] = item.value;
});
return new Promise((resolutionFunc, rejectionFunc) => {
api.cases
.paused(filters)
.then((response) => {
dt = that.formatDataResponse(response.data.data);
resolutionFunc({
data: dt,
count: response.data.total,
});
})
.catch((e) => {
rejectionFunc(e);
});
});
},
/**
* Get cases for Vue Card View
*/
getCasesViewMore(data) {
let that = this,
dt,
paged,
limit = data.limit,
start = data.page === 1 ? 0 : limit * (data.page - 1),
filters = {};
filters = {
limit: limit,
offset: start
};
_.forIn(this.filters, function (item, key) {
if (filters && item.value) {
filters[item.filterVar] = item.value;
}
});
return new Promise((resolutionFunc, rejectionFunc) => {
api.cases
.paused(filters)
.then((response) => {
dt = that.formatDataResponse(response.data.data);
resolutionFunc({
data: dt,
count: response.data.total,
});
})
.catch((e) => {
rejectionFunc(e);
});
});
},
/**
* Format columns for custom columns
* @param {*} headings
* @returns
*/
formatColumnSettings(headings) {
let res=[];
_.forEach(headings, function(value, key) {
if(key != "actions"){
res.push({value,key});
}
});
return res;
},
/**
* Formating the columns selected
* @param {*} columns
* @returns
*/
formatColumnSelected(columns) {
let cols = _.clone(columns);
cols.pop();
return cols;
},
/**
* Event handler when update the settings columns
* @param {*} columns
*/
onUpdateColumnSettings(columns) {
let cols = columns;
if(_.findIndex(cols, 'actions') == -1){
cols.push("actions");
}
this.columns = cols;
this.random = _.random(0, 10000000000);
}
}
}

View File

@@ -0,0 +1,162 @@
<template>
<div
id="v-pm-drill-down"
ref="v-pm-drill-down"
class="v-pm-drill-down vp-inline-block"
>
<div class="p-1 v-flex">
<h6 class="v-search-title">{{ $t("ID_DRILL_DOWN_NAVIGATOR") }}</h6>
</div>
<div
v-for="item in loadItems(data, level)"
:key="item.content"
class="vp-padding-b10"
@click="onClick(item)"
>
<span class="vp-inline-block vp-padding-r10 vp-font-size-r1">
{{ item.label }}
</span>
<div class="vp-inline-block">
<span :class="item.classObject"> {{ item.content }}</span>
</div>
</div>
</div>
</template>
<script>
import _ from "lodash";
export default {
name: "DrillDown",
mixins: [],
components: {},
props: ["level"],
data() {
let that = this;
return {
classObject: {
"rounded-circle": true,
"v-pm-drill-down-number": true,
"vp-btn-secondary": true,
"btn-primary": false,
"vp-block": true,
},
data: [
{
label: that.$t("ID_LEVEL"),
content: "0",
click() {
that.$emit("onChangeLevel", 0);
},
},
{
label: that.$t("ID_LEVEL"),
content: "1",
click() {
that.$emit("onChangeLevel", 1);
},
},
{
label: that.$t("ID_LEVEL"),
content: "2",
click() {
that.$emit("onChangeLevel", 2);
},
},
{
label: that.$t("ID_LEVEL"),
content: "3",
click() {},
},
],
};
},
created() {},
mounted() {},
watch: {},
computed: {},
updated() {},
beforeCreate() {},
methods: {
/**
* Click in drill option
*/
onClick(item) {
let array,
i = 0,
nindex;
array = _.clone(this.data);
array.forEach((el) => {
if (el.content === item.content) {
nindex = i;
}
i++;
});
this.index = nindex;
if (nindex <= this.level) {
item.click(item);
}
},
/**
* Load items in drill items
*/
loadItems(items, index) {
let array,
i = 0,
that = this;
array = _.clone(items);
array.forEach((el) => {
el.classObject = _.clone(that.classObject);
if (i <= index) {
el.classObject["vp-btn-secondary"] = false;
el.classObject["btn-primary"] = true;
}
i += 1;
});
return array;
},
},
};
</script>
<style>
.v-pm-drill-down-number {
height: 5rem;
width: 5rem;
text-align: center;
line-height: 5rem;
font-size: 1.5rem;
}
.vp-inline-block {
display: inline-block;
}
.vp-block {
display: block;
}
.vp-padding-r10 {
padding-right: 10px;
}
.vp-padding-b10 {
padding-bottom: 10px;
}
.vp-font-size-r1 {
font-size: 1rem;
}
.vp-btn-secondary {
color: #2f3133;
background-color: #b5b6b6;
}
.vp-btn-secondary:hover {
color: #fff;
background-color: #6c757d;
border-color: #6c757d;
}
.v-pm-drill-down {
vertical-align: top;
padding-left: 50px;
}
</style>

View File

@@ -0,0 +1,173 @@
<template>
<div class="pm-all-view-popover">
<b-popover
:target="target"
ref="popover"
triggers="click"
placement="bottom"
@show="onshow"
>
<template #title>{{ $t("ID_PROCESSES").toUpperCase() }}</template>
<div>
<div class="input-group input-group-sm mb-3">
<span class="input-group-text" id="inputGroup-sizing-sm"
><i class="fas fa-search"></i
></span>
<input
type="text"
class="form-control"
aria-describedby="inputGroup-sizing-sm"
@keyup="search"
v-model="text"
/>
</div>
<div class="form-check border-bottom">
<input
class="form-check-input"
type="checkbox"
v-model="allColumns"
@change="toogleAllColumns"
/>
<label class="form-check-label" for="flexCheckDefault">
{{ $t("ID_ALL") }}
</label>
</div>
<b-form-group>
<b-form-checkbox-group
v-model="localSelected"
:options="results"
value-field="key"
text-field="value"
name="flavour-2a"
@change="changeOptions"
stacked
></b-form-checkbox-group>
</b-form-group>
<div class="v-popover-footer">
<div class="float-right">
<b-button @click="onClose" size="sm" variant="danger">
{{ $t("ID_CANCEL") }}</b-button
>
<b-button @click="onSave" size="sm" variant="success">{{
$t("ID_SAVE")
}}</b-button>
</div>
</div>
</div>
</b-popover>
</div>
</template>
<script>
export default {
name: "ProcessPopover",
props: ["target"],
data() {
return {
options: [],
text: "",
results: [],
allColumns: false,
localSelected: [],
selected: [],
};
},
mounted() {
this.results = this.options;
this.localSelected = this.selected;
},
methods: {
/**
* Setter options for fill the popover
* @param {*} options
*/
setOptions(options) {
this.options = options;
this.results = options;
},
/**
* Setter the selected options
* @param {*} options
*/
setSelectedOptions(options) {
this.selected = options;
this.localSelected = options;
},
/**
* Close buton click handler
*/
onClose() {
this.$refs.popover.$emit("close");
this.$emit("closePopover");
},
/**
* Save button click handler
*/
onSave() {
let sels;
sels = _.clone(this.localSelected);
this.$root.$emit("bv::hide::popover");
this.$emit("onUpdateColumnSettings", sels);
},
/**
* Show popover event handler
*/
onshow() {
this.$root.$emit("bv::hide::popover");
},
/**
* Search in the column name
*/
search() {
let txt = this.text.toLowerCase(),
val,
opts = [];
opts = _.filter(this.options, function (o) {
val = o.value.toLowerCase();
return val.search(txt) != -1;
});
this.results = opts;
},
/**
* Toogle all options in popover
*/
toogleAllColumns() {
let res = [];
if (this.allColumns) {
_.each(this.options, function (o) {
res.push(o.key);
});
}
this.selected = res;
},
/**
* Handler when change options event
*/
changeOptions() {
let that = this,
res = [];
_.each(this.options, function (o) {
if (
_.findIndex(that.localSelected, function (v) {
return v === o.key;
}) != -1
) {
res.push(o.key);
}
});
this.localSelected = res;
},
},
};
</script>
<style scoped>
.pm-all-view-popover .popover {
max-width: 350px !important;
min-width: 200px !important;
}
.v-popover-footer {
display: flow-root;
}
</style>

View File

@@ -0,0 +1,79 @@
<template>
<div id="v-pm-task-metrics" ref="v-pm-task-metrics" class="v-pm-task-metrics">
<button-fleft :data="newCase"></button-fleft>
<div class="p-1 v-flex">
<h4 class="v-search-title">
Task metrics
<span class="vp-padding-r3"> <i class="fas fa-chart-pie"></i></span>
</h4>
</div>
<modal-new-request ref="newRequest"></modal-new-request>
<div class="d-inline-flex p-2">
<vue-charts
ref="pm-vue-chart"
@onChangeLevel="changeLevel"
:level="level"
/>
<div class="vp-6"></div>
<drill-down :level="level" @onChangeLevel="updateVueChart" />
</div>
</div>
</template>
<script>
import ButtonFleft from "../../components/home/ButtonFleft.vue";
import ModalNewRequest from "../ModalNewRequest.vue";
import DrillDown from "./DrillDown.vue";
import VueCharts from "./VueCharts.vue";
import defaultMixins from "./defaultMixins";
export default {
name: "TaskMetrics",
mixins: [defaultMixins],
components: {
ButtonFleft,
ModalNewRequest,
DrillDown,
VueCharts,
},
props: [],
data() {
let that = this;
return {
level: 0,
};
},
created() {},
mounted() {},
watch: {},
computed: {},
updated() {},
beforeCreate() {},
methods: {
/**
* Change level in drill down
*/
changeLevel(lv) {
this.level = lv;
},
/**
* update data in charts
*/
updateVueChart(lv) {
this.$refs["pm-vue-chart"].onChangeLevel(lv);
},
},
};
</script>
<style>
.v-pm-task-metrics {
padding-top: 20px;
padding-bottom: 20px;
padding-left: 50px;
padding-right: 50px;
}
.vp-padding-r3 {
padding-right: 3rem;
}
</style>

View File

@@ -0,0 +1,365 @@
<template>
<div id="v-pm-charts" ref="v-pm-charts" class="v-pm-charts vp-inline-block">
<div class="p-1 v-flex">
<h6 class="v-search-title">
{{ $t("ID_DRILL_DOWN_NUMBER_TASKS_PROCESS") }}
</h6>
<div>
<BreadCrumb
:options="breadCrumbs.data"
:settings="settingsBreadcrumbs"
/>
<ProcessPopover
:options="optionsProcesses"
target="pm-task-process"
ref="pm-task-process"
@onUpdateColumnSettings="onUpdateColumnSettings"
/>
<div class="vp-width-p40 vp-inline-block">
<multiselect
v-model="category"
:options="optionsCategory"
:searchable="false"
:close-on-select="true"
:show-labels="false"
track-by="id"
label="name"
@select="changeOption"
></multiselect>
</div>
<label class="vp-inline-block vp-padding-l20">{{
$t("ID_TOP")
}}</label>
<div class="vp-inline-block">
<b-form-checkbox
v-model="top"
name="check-button"
@change="changeOption"
switch
>
</b-form-checkbox>
</div>
<div class="vp-inline-block vp-right vp-padding-r40">
<h4
class="v-search-title"
@click="showProcessesPopover"
id="pm-task-process"
>
<i class="fas fa-cog"></i>
</h4>
</div>
</div>
<apexchart
ref="LevelOneChart"
:width="width"
:options="optionsBar"
:series="seriesBar"
></apexchart>
</div>
</div>
</template>
<script>
import _ from "lodash";
import Api from "../../api/index";
import BreadCrumb from "../../components/utils/BreadCrumb.vue";
import ProcessPopover from "./ProcessPopover.vue";
import Multiselect from "vue-multiselect";
export default {
name: "VueChartLvOne",
mixins: [],
components: {
Multiselect,
BreadCrumb,
ProcessPopover,
},
props: ["data", "breadCrumbs"],
data() {
let that = this;
return {
category: null,
dataProcesses: null, //Data API processes
settingsBreadcrumbs: [
{
class: "fas fa-info-circle",
tooltip: this.$t("ID_TASK_RISK_LEVEL1_INFO"),
onClick() {},
},
],
optionsCategory: [],
optionsProcesses: [],
selectedProcesses: [],
top: false,
width: 0,
totalCases: [],
currentSelection: null,
seriesBar: [
{
data: [],
},
],
optionsBar: {
chart: {
type: "bar",
id: "LevelOneChart",
toolbar: {
show: false,
},
events: {
legendClick: function (chartContext, seriesIndex, config) {
that.currentSelection = that.totalCases[seriesIndex];
that.$emit("updateDataLevel", {
id: that.currentSelection["PRO_ID"],
name: that.currentSelection["PRO_TITLE"],
level: 1,
data: that.currentSelection,
});
},
},
},
plotOptions: {
bar: {
barHeight: "100%",
distributed: true,
horizontal: true,
},
},
legend: {
position: "top",
},
colors: ["#33b2df", "#546E7A", "#d4526e", "#13d8aa"],
dataLabels: {
enabled: false,
},
xaxis: {
categories: [],
},
tooltip: {
x: {
show: false,
},
y: {
title: {
formatter: function () {
return "";
},
},
},
},
},
};
},
created() {},
mounted() {
this.getBodyHeight();
this.getCategories();
this.getProcesses();
},
watch: {},
computed: {},
updated() {},
beforeCreate() {},
methods: {
/**
* Return the height for Vue Card View body
*/
getBodyHeight() {
this.width = window.innerHeight;
},
/**
* Get Categories form API
*/
getCategories() {
let that = this;
Api.filters
.categories()
.then((response) => {
that.formatDataCategories(response.data);
})
.catch((e) => {
console.error(err);
});
},
/**
* Get Processes form API
*/
getProcesses() {
let that = this;
Api.filters
.processList("")
.then((response) => {
that.formatDataProcesses(response.data);
that.changeOption({
id: 0,
});
})
.catch((e) => {
console.error(err);
});
},
/**
* Format categories for multiselect
* @param {*} data
*/
formatDataCategories(data) {
let array = [];
array.push({
name: this.$t("ID_PROCESS_NONE_CATEGORY"),
id: "0",
});
_.each(data, (el) => {
array.push({ name: el["CATEGORY_NAME"], id: el["CATEGORY_ID"] });
});
this.optionsCategory = array;
this.category = array[0];
},
/**
* Format processes for popover
* @param {*} data
*/
formatDataProcesses(data) {
let sels = [],
labels = [],
array = [];
_.each(data, (el) => {
array.push({ value: el["PRO_TITLE"], key: el["PRO_ID"] });
sels.push(el["PRO_ID"]);
labels;
});
this.optionsProcesses = array;
this.selectedProcesses = sels;
//Update the labels
this.dataProcesses = data;
this.updateLabels(data);
},
/**
* Change the options in TOTAL CASES BY PROCESS
* @param {*} option
*/
changeOption(option) {
let that = this,
dt = {};
if (this.data.length > 0) {
dt = {
category: option.id,
caseList: this.data[0].id.toLowerCase(),
processes: this.selectedProcesses,
top: this.top,
};
Api.process
.totalCasesByProcess(dt)
.then((response) => {
that.totalCases = response.data;
that.formatTotalCases(response.data);
})
.catch((e) => {
console.error(err);
});
}
},
/**
* Show the processes popover
*/
showProcessesPopover() {
this.$root.$emit("bv::show::popover", "pm-task-process");
this.$refs["pm-task-process"].setOptions(this.optionsProcesses);
this.$refs["pm-task-process"].setSelectedOptions(this.selectedProcesses);
},
/**
* Format response form BE to chart
* @param {*} data
*/
formatTotalCases(data) {
let serie = [],
labels = [];
_.each(data, (el) => {
serie.push(el["TOTAL"]);
labels.push(el["PRO_TITLE"]);
});
this.$refs["LevelOneChart"].updateOptions({ labels: labels });
this.$apexcharts.exec("LevelOneChart", "updateSeries", [
{
data: serie,
},
]);
},
/**
* Update list processes in chart
* @param {*} data
*/
onUpdateColumnSettings(data) {
let res;
this.selectedProcesses = data;
res = _.intersectionBy(this.totalCases, data, (el) => {
if (_.isNumber(el)) {
return el;
}
if (_.isObject(el) && el["PRO_ID"]) {
return el["PRO_ID"];
}
});
this.formatTotalCases(res);
},
/**
* Update labels in chart
* @param {*} processes
*/
updateLabels(processes) {
let labels = [];
_.each(processes, (el) => {
labels.push(el["PRO_TITLE"]);
});
this.$refs["LevelOneChart"].updateOptions({ labels: labels });
},
/**
* UPdate serie in chart
* @param {*} processes
*/
updateSerie(processes) {
let labels = [];
_.each(processes, (el) => {
labels.push(el["TOTAL"]);
});
this.$refs["LevelOneChart"].updateOptions({ labels: labels });
},
/**
* Force update view when update level
*/
forceUpdateView() {
this.changeOption({
id: 0,
});
},
},
};
</script>
<style>
.vp-task-metrics-label {
display: inline-block;
}
.vp-width-p40 {
width: 40%;
}
.vp-inline-block {
display: inline-block;
}
.vp-padding-l20 {
padding-left: 20px;
}
.vp-padding-r40 {
padding-right: 40px;
}
.vp-right {
float: right;
}
</style>
<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>

View File

@@ -0,0 +1,493 @@
<template>
<div id="v-pm-charts" ref="v-pm-charts" class="v-pm-charts vp-inline-block">
<div class="p-1 v-flex">
<h6 class="v-search-title">{{$t("ID_DRILL_DOWN_RISK_MATRIX")}}</h6>
<div>
<BreadCrumb
:options="breadCrumbs.data"
:settings="settingsBreadcrumbs"
/>
<div class="vp-width-p30 vp-inline-block">
<b-form-datepicker
id="date-from"
:date-format-options="{
year: '2-digit',
month: '2-digit',
day: '2-digit',
}"
size="sm"
:placeholder="$t('ID_DELEGATE_DATE_FROM')"
v-model="dateFrom"
@input="changeOption"
></b-form-datepicker>
</div>
<div class="vp-width-p30 vp-inline-block">
<b-form-datepicker
id="date-to"
size="sm"
:date-format-options="{
year: '2-digit',
month: '2-digit',
day: '2-digit',
}"
:placeholder="$t('ID_DELEGATE_DATE_TO')"
v-model="dateTo"
@input="changeOption"
></b-form-datepicker>
</div>
<div class="vp-inline-block">
<label class="form-label">{{
$t("ID_TOP")
}}</label>
</div>
<div class="vp-inline-block">
<multiselect
v-model="size"
:options="sizeOptions"
:searchable="false"
:close-on-select="true"
:show-labels="false"
track-by="id"
label="name"
@input="changeOption"
></multiselect>
</div>
</div>
<apexchart
ref="LevelThreeChart"
:width="width"
:options="options"
:series="series"
></apexchart>
<div class="vp-width-p100">
<div class="vp-text-align-center" role="group">
<button
type="button"
@click="
riskType = 'ON_TIME';
changeOption();
"
class="btn vp-btn-success btn-sm"
>
On Time
</button>
<button
type="button"
@click="
riskType = 'AT_RISK';
changeOption();
"
class="btn vp-btn-warning btn-sm"
>
At Risk
</button>
<button
type="button"
@click="
riskType = 'OVERDUE';
changeOption();
"
class="btn vp-btn-danger btn-sm"
>
Overdue
</button>
</div>
</div>
<div class="vp-width-p100 vp-text-align-center">
<label class="vp-form-label">
{{ $t("ID_TODAY") }} : {{ dateNow }}
</label>
</div>
<ModalUnpauseCase ref="modal-unpause-case"></ModalUnpauseCase>
<ModalClaimCase ref="modal-claim-case"></ModalClaimCase>
</div>
</div>
</template>
<script>
import _ from "lodash";
import Api from "../../api/index";
import Multiselect from "vue-multiselect";
import BreadCrumb from "../../components/utils/BreadCrumb.vue";
import moment from "moment";
import ModalUnpauseCase from "../modal/ModalUnpauseCase.vue";
import ModalClaimCase from "../modal/ModalClaimCase.vue";
export default {
name: "VueChartLvThree",
mixins: [],
components: {
Multiselect,
BreadCrumb,
ModalUnpauseCase,
ModalClaimCase,
},
props: ["data", "breadCrumbs"],
data() {
let that = this;
return {
currentSelection: null,
dateFrom: "",
dateTo: "",
dateNow: "",
size: { name: this.$t("ID_ALL"), id: "all" },
riskType: "ON_TIME",
settingsBreadcrumbs: [
{
class: "fas fa-info-circle",
tooltip: this.$t("ID_TASK_RISK_LEVEL3_INFO"),
onClick() {},
},
],
sizeOptions: [
{ name: this.$t("ID_ALL"), id: "all" },
{ name: "5", id: "5" },
{ name: "10", id: "10" },
{ name: "15", id: "15" },
{ name: "20", id: "20" },
],
dataCasesByRisk: [],
width: 0,
series: [],
options: {
chart: {
height: 350,
type: "bubble",
zoom: {
enabled: true,
type: "xy",
},
id: "LevelThreeChart",
events: {
markerClick: function (event, chartContext, config) {
that.currentSelection = that.dataCasesByRisk[config.seriesIndex];
that.onClickCaseMarker(that.currentSelection);
},
},
},
legend: {
show: false,
},
dataLabels: {
enabled: true,
formatter: function (val, opt) {
if (that.dataCasesByRisk.length > 0) {
return that.dataCasesByRisk[opt["seriesIndex"]]["number_case"];
}
return "";
},
offsetX: 0,
},
xaxis: {
type: "datetime",
},
yaxis: {
tickAmount: 1,
},
tooltip: {
custom: function ({ series, seriesIndex, dataPointIndex, w }) {
return that.customTooltip(series, seriesIndex, dataPointIndex, w);
},
},
},
};
},
created() {},
mounted() {
this.getBodyHeight();
},
watch: {},
computed: {},
updated() {},
beforeCreate() {},
methods: {
/**
* Return the height for Vue Card View body
*/
getBodyHeight() {
this.width = window.innerHeight * 0.95;
},
/**
* Change datepickers or radio button
*/
changeOption() {
let that = this,
dt;
if (this.dateFrom && this.dateTo) {
dt = {
process: this.data[1].id,
caseList: this.data[0].id.toLowerCase(),
dateFrom: moment(this.dateFrom).format("DD/MM/YYYY"),
dateTo: moment(this.dateTo).format("DD/MM/YYYY"),
riskStatus: this.riskType,
};
this.size.id != "all" ? (dt["topCases"] = this.size.id) : null;
this.dateNow = moment().format("DD/MM/YYYY h:mm:ss a");
Api.process
.totalCasesByRisk(dt)
.then((response) => {
that.formatDataRange(response.data);
})
.catch((e) => {
console.error(err);
});
}
},
/**
* Format response fromn API
* @param {object} data
*/
formatDataRange(data) {
let that = this,
serie = [];
this.dataCasesByRisk = data;
_.each(data, (el) => {
//Format the response to risk type Overdue/At risk/ On time
switch (that.riskType) {
case "OVERDUE":
serie.push({
name: el["number_case"].toString(),
data: [
[moment(el["due_date"]).toDate().getTime(), el["days"], 20],
],
});
break;
case "AT_RISK":
serie.push({
name: el["number_case"].toString(),
data: [
[moment(el["delegated"]).toDate().getTime(), -el["days"], 20],
],
});
break;
case "ON_TIME":
serie.push({
name: el["number_case"].toString(),
data: [
[moment(el["delegated"]).toDate().getTime(), -el["days"], 20],
],
});
break;
}
});
this.updateApexchartAxis();
if (this.data[0].id.toLowerCase() == "draft") {
this.series = []; // Draft is empty
} else {
this.series = serie;
}
},
/**
* Update axis chart
*/
updateApexchartAxis() {
switch (this.riskType) {
case "OVERDUE":
this.$refs["LevelThreeChart"].updateOptions({
yaxis: {
min: 0,
},
title: {
text: "Overdue days",
},
});
break;
case "AT_RISK":
this.$refs["LevelThreeChart"].updateOptions({
yaxis: {
max: 0,
},
title: {
text: "Days before being Overdue",
},
});
break;
case "ON_TIME":
this.$refs["LevelThreeChart"].updateOptions({
yaxis: {
max: 0,
},
title: {
text: "Days before being At-Risk",
},
});
break;
}
},
/**
* Create custom tooltip
*/
customTooltip(series, seriesIndex, dataPointIndex, w) {
let obj = this.dataCasesByRisk[seriesIndex];
return `<div class="apexcharts-theme-light">
<div class="apexcharts-tooltip-title" style="font-family: Helvetica, Arial, sans-serif; font-size: 12px;">
${"Number Case"} : ${obj["number_case"]}
</div>
<div class="apexcharts-tooltip-series-group apexcharts-active" style="order: 1; display: flex;">
<div class="apexcharts-tooltip-text" style="font-family: Helvetica, Arial, sans-serif; font-size: 12px;">
<div class="apexcharts-tooltip-y-group">
<span class="" style="background-color: #28a745;"></span>
<span class="apexcharts-tooltip-text-y-label">Delegated</span> : <span class="apexcharts-tooltip-text-y-value">${
obj["delegated"]
}</span>
</div>
<div class="apexcharts-tooltip-y-group">
<span class="" style="background-color: #28a745;"></span>
<span class="apexcharts-tooltip-text-y-label">At Risk</span> : <span class="apexcharts-tooltip-text-y-value">${
obj["at_risk"]
}</span>
</div>
<div class="apexcharts-tooltip-y-group">
<span class="" style="background-color: #28a745;"></span>
<span class="apexcharts-tooltip-text-y-label">Due Date</span> : <span class="apexcharts-tooltip-text-y-value">${
obj["due_date"]
}</span>
</div>
</div>
</div>
</div>`;
},
/**
* Open selected cases in the inbox
* @param {object} item
*/
openCase(item) {
this.$parent.$parent.$emit("onUpdateDataCase", {
APP_UID: item.APP_UID,
DEL_INDEX: item.DEL_INDEX,
PRO_UID: item.PRO_UID,
TAS_UID: item.TAS_UID,
ACTION: "todo",
});
this.$parent.$parent.$emit("onUpdatePage", "XCase");
},
/**
* Click in marker chart
* @param {object} selection
*/
onClickCaseMarker(selection) {
let process = this.data[1].id,
caseList = this.data[0].id.toLowerCase();
switch (caseList) {
case "inbox":
case "draft":
this.openCase({
APP_UID: selection["app_uid"],
DEL_INDEX: selection["del_index"],
PRO_UID: process,
TAS_UID: selection["tas_uid"],
});
break;
case "paused":
this.showModalUnpauseCase({
APP_UID: selection["app_uid"],
DEL_INDEX: selection["del_index"],
PRO_UID: process,
TAS_UID: selection["tas_uid"],
});
break;
case "unassigned":
this.showModalClaimCase({
APP_UID: selection["app_uid"],
DEL_INDEX: selection["del_index"],
PRO_UID: process,
TAS_UID: selection["tas_uid"],
});
break;
}
},
/**
* Show modal unpause
* @param {object} item
*/
showModalUnpauseCase(item) {
this.$refs["modal-unpause-case"].data = item;
this.$refs["modal-unpause-case"].show();
},
/**
* Claim case
* @param {object} item
*/
showModalClaimCase(item) {
let that = this;
api.cases.open(_.extend({ ACTION: "unassigned" }, item)).then(() => {
api.cases.cases_open(_.extend({ ACTION: "todo" }, item)).then(() => {
that.$refs["modal-claim-case"].data = item;
that.$refs["modal-claim-case"].show();
});
});
},
},
};
</script>
<style>
.vp-task-metrics-label {
display: inline-block;
}
.vp-width-p30 {
width: 30%;
}
.vp-inline-block {
display: inline-block;
}
.vp-padding-l20 {
padding-left: 20px;
}
.vp-width-p100 {
width: 100%;
}
.vp-text-align-center {
text-align: center;
}
.vp-btn-success {
color: #fff;
background-color: #368b48;
border-color: #368b48;
}
.vp-btn-success:hover {
color: #fff;
background-color: #255a30;
border-color: #368b48;
}
.vp-btn-warning {
color: #fff;
background-color: #c99e11;
border-color: #a1831d;
}
.vp-btn-warning:hover {
color: #fff;
background-color: #886c0e;
border-color: #a1831d;
}
.vp-btn-danger {
color: #fff;
background-color: #b63b32;
border-color: #b63b32;
}
.vp-btn-danger:hover {
color: #fff;
background-color: #832923;
border-color: #b63b32;
}
.vp-form-label {
display: inline-block;
font-family: Helvetica, Arial, sans-serif;
text-anchor: start;
font-size: 14px;
font-weight: 900;
fill: rgb(15 17 18);
margin-top: 0.5rem;
color: #7d7f93;
}
</style>
<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>

View File

@@ -0,0 +1,219 @@
<template>
<div id="v-pm-charts" ref="v-pm-charts" class="v-pm-charts vp-inline-block">
<div class="p-1 v-flex">
<h6 class="v-search-title">{{$t("ID_DRILL_DOWN_NUMBER_TASKS_PROCESS_BY_TASK")}}</h6>
<div>
<BreadCrumb
:options="breadCrumbs.data"
:settings="settingsBreadcrumbs"
/>
<div class="vp-width-p30 vp-inline-block">
<b-form-datepicker
id="date-from"
:date-format-options="{
year: '2-digit',
month: '2-digit',
day: '2-digit',
}"
size="sm"
:placeholder="$t('ID_DELEGATE_DATE_FROM')"
v-model="dateFrom"
@input="changeOption"
></b-form-datepicker>
</div>
<div class="vp-width-p30 vp-inline-block">
<b-form-datepicker
id="date-to"
size="sm"
:date-format-options="{
year: '2-digit',
month: '2-digit',
day: '2-digit',
}"
:placeholder="$t('ID_DELEGATE_DATE_TO')"
v-model="dateTo"
@input="changeOption"
></b-form-datepicker>
</div>
<div class="vp-inline-block">
<b-form-radio-group
id="btn-radios"
v-model="period"
:options="periodOptions"
button-variant="outline-secondary"
size="sm"
name="radio-btn-outline"
buttons
@change="changeOption"
></b-form-radio-group>
</div>
</div>
<apexchart
ref="LevelTwoChart"
:width="width"
:options="options"
:series="series"
></apexchart>
</div>
</div>
</template>
<script>
import _ from "lodash";
import Api from "../../api/index";
import Multiselect from "vue-multiselect";
import BreadCrumb from "../../components/utils/BreadCrumb.vue";
import moment from "moment";
export default {
name: "VueChartLvTwo",
mixins: [],
components: {
Multiselect,
BreadCrumb,
},
props: ["data", "breadCrumbs"],
data() {
let that = this;
return {
dateFrom: "",
dateTo: "",
period: "",
periodOptions: [
{ text: this.$t("ID_DAY"), value: "day" },
{ text: this.$t("ID_MONTH"), value: "month" },
{ text: this.$t("ID_YEAR"), value: "year" },
],
settingsBreadcrumbs: [
{
class: "fas fa-info-circle",
tooltip: this.$t("ID_TASK_RISK_LEVEL2_INFO"),
onClick() {},
},
],
dataCasesByRange: [],
width: 0,
options: {
chart: {
type: "area",
zoom: {
enabled: false,
},
id: "LevelTwoChart",
events: {
markerClick: function (event, chartContext, config) {
that.currentSelection = that.dataCasesByRange[config.seriesIndex];
that.$emit("updateDataLevel", {
id: that.currentSelection["PRO_ID"],
name: that.currentSelection["PRO_TITLE"],
level: 2,
data: null,
});
},
},
},
dataLabels: {
enabled: false,
},
stroke: {
curve: "smooth",
},
xaxis: {
type: "datetime",
},
tooltip: {
fixed: {
enabled: false,
position: "topRight",
},
},
},
series: [],
};
},
created() {},
mounted() {
this.getBodyHeight();
},
watch: {},
computed: {},
updated() {},
beforeCreate() {},
methods: {
/**
* Return the height for Vue Card View body
*/
getBodyHeight() {
this.width = window.innerHeight;
},
/**
* Change datepickers or radio button
*/
changeOption() {
let that = this,
dt;
if (this.dateFrom && this.dateTo && this.period) {
dt = {
processId: this.data[1].id,
caseList: this.data[0].id.toLowerCase(),
dateFrom: moment(this.dateFrom).format("DD/MM/YYYY"),
dateTo: moment(this.dateTo).format("DD/MM/YYYY"),
groupBy: this.period,
};
Api.process
.totalCasesByRange(dt)
.then((response) => {
that.formatDataRange(response.data);
})
.catch((e) => {
console.error(e);
});
}
},
/**
* Format response from API
* @param {object} data
*/
formatDataRange(data) {
let labels = [],
serie = [];
this.dataCasesByRange = data;
_.each(data, (el) => {
serie.push(el["TOTAL"]);
labels.push(el["dateGroup"]);
});
this.$refs["LevelTwoChart"].updateOptions({
labels: labels,
title: {
text: this.data[0]["PRO_TITLE"],
align: "left",
},
});
this.$apexcharts.exec("LevelTwoChart", "updateSeries", [
{
name: this.data[0]["PRO_TITLE"],
data: serie,
},
]);
},
},
};
</script>
<style>
.vp-task-metrics-label {
display: inline-block;
}
.vp-width-p30 {
width: 30%;
}
.vp-inline-block {
display: inline-block;
}
.vp-padding-l20 {
padding-left: 20px;
}
</style>
<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>

View File

@@ -0,0 +1,248 @@
<template>
<div id="v-pm-charts" ref="v-pm-charts" class="v-pm-charts vp-inline-block">
<div class="p-1 v-flex">
<h6 class="v-search-title">{{$t("ID_DRILL_DOWN_NUMBER_TASKS")}}</h6>
<BreadCrumb :options="breadCrumbs.data" :settings="settingsBreadcrumbs" />
<apexchart
v-show="typeView === 'donut'"
ref="apexchart1"
:width="width"
:options="optionsDonut"
:series="seriesDonut"
></apexchart>
<apexchart
v-show="typeView === 'bar'"
ref="apexchart2"
:width="width"
:options="optionsBar"
:series="seriesBar"
></apexchart>
<div class="row">
<div class="col-sm vp-align-right">
<button
@click="changeView('donut')"
type="button"
class="btn btn-primary"
>
<i class="fas fa-chart-pie"></i
><span class="vp-padding-l10">{{ $t("ID_VIEW") }}</span>
</button>
</div>
<div class="col-sm">
<button
@click="changeView('bar')"
type="button"
class="btn btn-primary"
>
<i class="fas fa-chart-bar"></i
><span class="vp-padding-l10">{{ $t("ID_VIEW") }}</span>
</button>
</div>
</div>
</div>
</div>
</template>
<script>
import _ from "lodash";
import Api from "../../api/index";
import BreadCrumb from "./../../components/utils/BreadCrumb.vue";
export default {
name: "VueChartLvZero",
mixins: [],
components: { BreadCrumb },
props: ["breadCrumbs"],
data() {
let that = this;
return {
typeView: "donut",
width: 0,
data: [],
currentSelection: null,
seriesDonut: [],
settingsBreadcrumbs: [
{
class: "fas fa-info-circle",
tooltip: this.$t("ID_TASK_RISK_LEVEL0_INFO"),
onClick() {},
},
],
optionsDonut: {
labels: [
this.$i18n.t("ID_INBOX"),
this.$i18n.t("ID_DRAFT"),
this.$i18n.t("ID_PAUSED"),
this.$i18n.t("ID_UNASSIGNED"),
],
chart: {
id: "apexchart1",
type: "donut",
events: {
legendClick: function (chartContext, seriesIndex, config) {
that.currentSelection = that.data[seriesIndex];
that.$emit("updateDataLevel", {
id: that.currentSelection["List Name"],
name: that.currentSelection["List Name"],
level: 0,
data: that.currentSelection,
});
},
},
},
legend: {
position: "top",
offsetY: 0,
},
},
seriesBar: [
{
data: [400, 430, 448, 470],
},
],
optionsBar: {
chart: {
type: "bar",
id: "apexchart2",
toolbar: {
show: false,
},
events: {
legendClick: function (chartContext, seriesIndex, config) {
that.currentSelection = that.data[seriesIndex];
that.$emit("updateDataLevel", {
id: that.currentSelection["List Name"],
name: that.currentSelection["List Name"],
level: 0,
data: that.currentSelection,
});
},
},
},
plotOptions: {
bar: {
barHeight: "100%",
distributed: true,
},
},
legend: {
position: "top",
offsetY: 0,
},
colors: ["#33b2df", "#546E7A", "#d4526e", "#13d8aa"],
dataLabels: {
enabled: false,
},
xaxis: {
categories: [
this.$i18n.t("ID_INBOX"),
this.$i18n.t("ID_DRAFT"),
this.$i18n.t("ID_PAUSED"),
this.$i18n.t("ID_UNASSIGNED"),
],
},
tooltip: {
x: {
show: false,
},
y: {
title: {
formatter: function () {
return "";
},
},
},
},
},
};
},
created() {},
mounted() {
this.getBodyHeight();
this.getData();
},
watch: {},
computed: {},
updated() {},
beforeCreate() {},
methods: {
/**
* Return the height for Vue Card View body
*/
getBodyHeight() {
this.width = window.innerHeight * 0.8;
},
/**
* Change view - donut/bar
*/
changeView(view) {
this.typeView = view;
this.getData();
},
/**
* Get data from rest API
*/
getData() {
let that = this;
Api.cases
.listTotalCases()
.then((response) => {
that.formatData(response.data);
})
.catch((response) => {});
},
/**
* Format the data for chart
*/
formatData(data) {
let l = [],
c = [],
s = [];
_.each(data, (el) => {
l.push(el["List Name"]);
s.push(el["Total"]);
if (el["Color"] == "green") {
c.push("#179a6e");
}
if (el["Color"] == "yellow") {
c.push("#feb019");
}
if (el["Color"] == "blue") {
c.push("#008ffb");
}
if (el["Color"] == "gray") {
c.push("#8f99a0");
}
});
this.data = data;
this.seriesDonut = s;
this.seriesBar = [
{
data: s,
},
];
this.$refs["apexchart1"].updateOptions({ labels: l, colors: c });
this.$refs["apexchart2"].updateOptions({ labels: l, colors: c });
this.$apexcharts.exec("apexchart1", "updateSeries", s);
this.$apexcharts.exec("apexchart2", "updateSeries", [
{
data: s,
},
]);
},
},
};
</script>
<style>
.vp-center {
text-align: center;
}
.vp-align-right {
text-align: right;
}
.vp-padding-l10 {
padding-left: 10px;
}
</style>

View File

@@ -0,0 +1,157 @@
<template>
<div id="v-pm-charts" ref="v-pm-charts" class="v-pm-charts vp-inline-block">
<vue-chart-lv-zero
v-show="level === 0"
@updateDataLevel="updateDataLevel"
:breadCrumbs="dataBreadCrumbs()"
/>
<vue-chart-lv-one
:key="key1"
v-show="level === 1"
:data="data"
@onChangeLevel="onChangeLevel"
@updateDataLevel="updateDataLevel"
:breadCrumbs="dataBreadCrumbs()"
/>
<vue-chart-lv-two
:key="key2"
v-show="level === 2"
:data="data"
@onChangeLevel="onChangeLevel"
@updateDataLevel="updateDataLevel"
:breadCrumbs="dataBreadCrumbs()"
/>
<vue-chart-lv-three
:key="key3"
v-show="level === 3"
:data="data"
@onChangeLevel="onChangeLevel"
:breadCrumbs="dataBreadCrumbs()"
/>
</div>
</template>
<script>
import VueChartLvZero from "./VueChartLvZero.vue";
import VueChartLvOne from "./VueChartLvOne.vue";
import VueChartLvTwo from "./VueChartLvTwo.vue";
import VueChartLvThree from "./VueChartLvThree.vue";
export default {
name: "VueCharts",
mixins: [],
components: {
VueChartLvZero,
VueChartLvOne,
VueChartLvTwo,
VueChartLvThree,
},
props: [],
data() {
let that = this;
return {
level: 0,
key1: 1,
key2: 1,
key3: 1,
data: [],
settingsBreadCrumbs: [
{
class: "fas fa-info-circle",
onClick() {},
},
],
};
},
created() {},
mounted() {},
watch: {},
computed: {},
updated() {},
beforeCreate() {},
methods: {
/**
* Set data level 0
*/
updateDataLevel(data) {
this.data.push(data);
this.level = data.level + 1;
this.$emit("onChangeLevel", data.level + 1);
this.updateKey();
},
updateKey() {
switch (this.level) {
case 0:
break;
case 1:
this.key1++;
break;
case 2:
this.key2++;
break;
case 3:
this.key3++;
break;
}
},
/**
* Format data to vue charts any level
*/
formatData() {
return {
level: this.level,
data: this.data,
};
},
/**
* Change level with changes in data
* @param {object} lv
*/
onChangeLevel(lv) {
_.remove(this.data, function (n) {
return n.level >= lv;
});
this.level = lv;
this.$emit("onChangeLevel", this.level);
},
/**
* Format data for data beadcrumbs
*/
dataBreadCrumbs() {
let res = [],
that = this,
index = 0;
_.each(this.data, (el) => {
if (index <= that.level && el.data) {
res.push({
label: el.name,
onClick() {
that.onChangeLevel(el.level);
},
});
}
});
res.push({
label: this.$t("ID_SELECT"),
onClick() {},
});
switch (this.level) {
case 0:
return {
data: res,
settings: this.settingsBreadCrumbs,
};
break;
default:
return {
data: res,
settings: this.settingsBreadCrumbs,
};
break;
}
}
},
};
</script>
<style>
</style>

View File

@@ -0,0 +1,16 @@
import _ from "lodash";
import api from "../../api/index";
export default {
data() {
let that = this;
return {
newCase: {
title: this.$i18n.t("ID_NEW_CASE"),
class: "btn-success",
onClick: () => {
this.$refs["newRequest"].show();
},
},
}
}
}

View File

@@ -1,365 +0,0 @@
<template>
<div id="v-todo" ref="v-todo" class="v-container-todo">
<button-fleft :data="newCase"></button-fleft>
<modal-new-request ref="newRequest"></modal-new-request>
<CasesFilter
:filters="filters"
:title="$t('ID_CASES_STATUS_TO_DO')"
@onRemoveFilter="onRemoveFilter"
@onUpdateFilters="onUpdateFilters"
/>
<v-server-table
:data="tableData"
:columns="columns"
:options="options"
ref="vueTable"
@row-click="onRowClick"
>
<div slot="detail" slot-scope="props">
<div class="btn-default" @click="openCaseDetail(props.row)">
<i class="fas fa-info-circle"></i>
</div>
</div>
<div slot="case_number" slot-scope="props">
{{ props.row.CASE_NUMBER }}
</div>
<div slot="case_title" slot-scope="props">
{{ props.row.CASE_TITLE }}
</div>
<div slot="process_name" slot-scope="props">
{{ props.row.PROCESS_NAME }}
</div>
<div slot="task" slot-scope="props">
<TaskCell :data="props.row.TASK" />
</div>
<div slot="current_user" slot-scope="props">
{{ props.row.USERNAME_DISPLAY_FORMAT}}
</div>
<div slot="due_date" slot-scope="props">
{{ props.row.DUE_DATE }}
</div>
<div slot="delegation_date" slot-scope="props">
{{ props.row.DELEGATION_DATE }}
</div>
<div slot="priority" slot-scope="props">{{ props.row.PRIORITY }}</div>
<div slot="actions" slot-scope="props">
<button class="btn btn-success btn-sm" @click="openCase(props.row)">
{{ $t("ID_OPEN_CASE") }}
</button>
</div>
</v-server-table>
</div>
</template>
<script>
import HeaderCounter from "../components/home/HeaderCounter.vue";
import ButtonFleft from "../components/home/ButtonFleft.vue";
import ModalNewRequest from "./ModalNewRequest.vue";
import TaskCell from "../components/vuetable/TaskCell.vue";
import CasesFilter from "../components/search/CasesFilter";
import api from "./../api/index";
import utils from "./../utils/utils";
export default {
name: "Todo",
components: {
HeaderCounter,
ButtonFleft,
ModalNewRequest,
TaskCell,
CasesFilter,
},
props: ["defaultOption", "filters"],
data() {
return {
newCase: {
title: this.$i18n.t("ID_NEW_CASE"),
class: "btn-success",
onClick: () => {
this.$refs["newRequest"].show();
},
},
columns: [
"detail",
"case_number",
"case_title",
"process_name",
"task",
"due_date",
"delegation_date",
"priority",
"actions",
],
tableData: [],
options: {
filterable: false,
headings: {
detail: "",
case_number: this.$i18n.t("ID_MYCASE_NUMBER"),
case_title: this.$i18n.t("ID_CASE_TITLE"),
process_name: this.$i18n.t("ID_PROCESS_NAME"),
task: this.$i18n.t("ID_TASK"),
current_user: this.$i18n.t("ID_CURRENT_USER"),
due_date: this.$i18n.t("ID_DUE_DATE"),
delegation_date: this.$i18n.t("ID_DELEGATION_DATE"),
priority: this.$i18n.t("ID_PRIORITY"),
actions: "",
},
texts: {
count:this.$i18n.t("ID_SHOWING_FROM_RECORDS_COUNT"),
first: this.$i18n.t("ID_FIRST"),
last: this.$i18n.t("ID_LAST"),
filter: this.$i18n.t("ID_FILTER") + ":",
limit: this.$i18n.t("ID_RECORDS") + ":",
page: this.$i18n.t("ID_PAGE") + ":",
noResults: this.$i18n.t("ID_NO_MATCHING_RECORDS")
},
selectable: {
mode: "single",
only: function (row) {
return true;
},
selectAllMode: "page",
programmatic: false,
},
requestFunction(data) {
return this.$parent.$parent.getCasesForVueTable(data);
},
},
pmDateFormat: "Y-m-d H:i:s",
clickCount: 0,
singleClickTimer: null,
statusTitle: {
"ON_TIME": this.$i18n.t("ID_IN_PROGRESS"),
"OVERDUE": this.$i18n.t("ID_TASK_OVERDUE"),
"DRAFT": this.$i18n.t("ID_IN_DRAFT"),
"PAUSED": this.$i18n.t("ID_PAUSED"),
"UNASSIGNED": this.$i18n.t("ID_UNASSIGNED")
}
};
},
created() {
this.initFilters();
},
mounted() {
// force to open case
this.openDefaultCase();
},
watch: {},
computed: {
/**
* Build our ProcessMaker apiClient
*/
ProcessMaker() {
return window.ProcessMaker;
},
},
updated() {},
beforeCreate() {},
methods: {
/**
* Initialize filters
*/
initFilters() {
let params;
if(this.defaultOption) {
params = utils.getAllUrlParams(this.defaultOption);
if (params && params.openapplicationuid) {
this.$emit("onUpdateFilters", [
{
fieldId: "caseNumber",
filterVar: "caseNumber",
label: "",
options:[],
value: params.openapplicationuid,
autoShow: false
}
]);
}
}
},
/**
* Open a case when the component was mounted
*/
openDefaultCase() {
let params;
if(this.defaultOption) {
params = utils.getAllUrlParams(this.defaultOption);
if (params && params.app_uid && params.del_index) {
this.openCase({
APP_UID: params.app_uid,
DEL_INDEX: params.del_index
});
this.$emit("cleanDefaultOption");
}
//force to search in the parallel tasks
if (params && params.openapplicationuid) {
this.onUpdateFilters({
params: [
{
fieldId: "caseNumber",
filterVar: "caseNumber",
label: "",
options:[],
value: params.openapplicationuid,
autoShow: false
}
],
refresh: false
});
this.$emit("cleanDefaultOption");
}
}
},
/**
* On row click event handler
* @param {object} event
*/
onRowClick(event) {
let self = this;
self.clickCount += 1;
if (self.clickCount === 1) {
self.singleClickTimer = setTimeout(function() {
self.clickCount = 0;
}, 400);
} else if (self.clickCount === 2) {
clearTimeout(self.singleClickTimer);
self.clickCount = 0;
self.openCase(event.row);
}
},
/**
* Get cases todo data
*/
getCasesForVueTable(data) {
let that = this,
dt,
paged,
limit = data.limit,
start = data.page === 1 ? 0 : limit * (data.page - 1),
filters = {};
paged = start + "," + limit;
filters = {
paged: paged,
};
_.forIn(this.filters, function (item, key) {
filters[item.filterVar] = item.value;
});
return new Promise((resolutionFunc, rejectionFunc) => {
api.cases
.todo(filters)
.then((response) => {
dt = that.formatDataResponse(response.data.data);
resolutionFunc({
data: dt,
count: response.data.total,
});
})
.catch((e) => {
rejectionFunc(e);
});
});
},
/**
* Format Response API TODO to grid todo and columns
*/
formatDataResponse(response) {
let data = [];
_.forEach(response, (v) => {
data.push({
CASE_NUMBER: v.APP_NUMBER,
CASE_TITLE: v.DEL_TITLE,
PROCESS_NAME: v.PRO_TITLE,
TASK: [{
TITLE: v.TAS_TITLE,
CODE_COLOR: v.TAS_COLOR,
COLOR: v.TAS_COLOR_LABEL,
DELAYED_TITLE: v.TAS_STATUS === "OVERDUE" ?
this.$i18n.t("ID_DELAYED") + ":" : this.statusTitle[v.TAS_STATUS],
DELAYED_MSG: v.TAS_STATUS === "OVERDUE" ? v.DELAY : ""
}],
USERNAME_DISPLAY_FORMAT: utils.userNameDisplayFormat({
userName: v.USR_LASTNAME,
firstName: v.USR_LASTNAME,
lastName: v.USR_LASTNAME,
format: window.config.FORMATS.format || null
}),
DUE_DATE: v.DEL_TASK_DUE_DATE_LABEL,
DELEGATION_DATE: v.DEL_DELEGATE_DATE_LABEL,
PRIORITY: v.DEL_PRIORITY_LABEL,
DEL_INDEX: v.DEL_INDEX,
APP_UID: v.APP_UID,
PRO_UID: v.PRO_UID,
TAS_UID: v.TAS_UID,
});
});
return data;
},
/**
* Open selected cases in the inbox
*
* @param {object} item
*/
openCase(item) {
this.$emit("onUpdateDataCase", {
APP_UID: item.APP_UID,
DEL_INDEX: item.DEL_INDEX,
PRO_UID: item.PRO_UID,
TAS_UID: item.TAS_UID,
ACTION: "todo"
});
this.$emit("onUpdatePage", "XCase");
},
/**
* Open case detail
*
* @param {object} item
*/
openCaseDetail(item) {
let that = this;
api.cases.open(_.extend({ ACTION: "todo" }, item)).then(() => {
api.cases.cases_open(_.extend({ ACTION: "todo" }, item)).then(() => {
that.$emit("onUpdateDataCase", {
APP_UID: item.APP_UID,
DEL_INDEX: item.DEL_INDEX,
PRO_UID: item.PRO_UID,
TAS_UID: item.TAS_UID,
APP_NUMBER: item.CASE_NUMBER,
ACTION: "todo"
});
that.$emit("onUpdatePage", "case-detail");
});
});
},
onRemoveFilter(data) {},
onUpdateFilters(data) {
this.$emit("onUpdateFilters", data.params);
if (data.refresh) {
this.$nextTick(() => {
this.$refs["vueTable"].getData();
});
}
},
/**
* update view in component
*/
updateView(){
this.$refs["vueTable"].getData();
}
},
};
</script>
<style>
.v-container-todo {
padding-top: 20px;
padding-bottom: 20px;
padding-left: 50px;
padding-right: 50px;
}
.VueTables__limit {
display: none;
}
</style>

View File

@@ -1,342 +0,0 @@
<template>
<div id="v-unassigned" ref="v-unassigned" class="v-container-unassigned">
<button-fleft :data="newCase"></button-fleft>
<modal-new-request ref="newRequest"></modal-new-request>
<CasesFilter
:filters="filters"
:title="$t('ID_UNASSIGNED')"
@onRemoveFilter="onRemoveFilter"
@onUpdateFilters="onUpdateFilters"
/>
<v-server-table
:data="tableData"
:columns="columns"
:options="options"
ref="vueTable"
@row-click="onRowClick"
>
<div slot="detail" slot-scope="props">
<div class="btn-default" @click="openCaseDetail(props.row)">
<i class="fas fa-info-circle"></i>
</div>
</div>
<div slot="case_number" slot-scope="props">
{{ props.row.CASE_NUMBER }}
</div>
<div slot="case_title" slot-scope="props">
{{ props.row.CASE_TITLE }}
</div>
<div slot="process_name" slot-scope="props">
{{ props.row.PROCESS_NAME }}
</div>
<div slot="task" slot-scope="props">
<TaskCell :data="props.row.TASK" />
</div>
<div slot="due_date" slot-scope="props">
{{ props.row.DUE_DATE }}
</div>
<div slot="delegation_date" slot-scope="props">
{{ props.row.DELEGATION_DATE }}
</div>
<div slot="priority" slot-scope="props">{{ props.row.PRIORITY }}</div>
<div slot="actions" slot-scope="props">
<button class="btn btn-success btn-sm" @click="claimCase(props.row)">
{{ $t("ID_CLAIM") }}
</button>
</div>
</v-server-table>
<ModalClaimCase ref="modal-claim-case"></ModalClaimCase>
</div>
</template>
<script>
import HeaderCounter from "../components/home/HeaderCounter.vue";
import ButtonFleft from "../components/home/ButtonFleft.vue";
import ModalNewRequest from "./ModalNewRequest.vue";
import TaskCell from "../components/vuetable/TaskCell.vue";
import CasesFilter from "../components/search/CasesFilter";
import ModalClaimCase from "./modal/ModalClaimCase.vue";
import api from "./../api/index";
import utils from "./../utils/utils";
export default {
name: "Unassigned",
components: {
HeaderCounter,
ButtonFleft,
ModalNewRequest,
TaskCell,
ModalClaimCase,
CasesFilter,
},
props: ["defaultOption", "filters"],
data() {
return {
newCase: {
title: this.$i18n.t("ID_NEW_CASE"),
class: "btn-success",
onClick: () => {
this.$refs["newRequest"].show();
},
},
columns: [
"detail",
"case_number",
"case_title",
"process_name",
"task",
"due_date",
"delegation_date",
"priority",
"actions",
],
tableData: [],
options: {
filterable: false,
sendInitialRequest: false,
headings: {
case_number: this.$i18n.t("ID_MYCASE_NUMBER"),
case_title: this.$i18n.t("ID_CASE_TITLE"),
process_name: this.$i18n.t("ID_PROCESS_NAME"),
task: this.$i18n.t("ID_TASK"),
current_user: this.$i18n.t("ID_CURRENT_USER"),
due_date: this.$i18n.t("ID_DUE_DATE"),
delegation_date: this.$i18n.t("ID_DELEGATION_DATE"),
priority: this.$i18n.t("ID_PRIORITY"),
actions: "",
detail: "",
},
texts: {
count:this.$i18n.t("ID_SHOWING_FROM_RECORDS_COUNT"),
first: this.$i18n.t("ID_FIRST"),
last: this.$i18n.t("ID_LAST"),
filter: this.$i18n.t("ID_FILTER") + ":",
limit: this.$i18n.t("ID_RECORDS") + ":",
page: this.$i18n.t("ID_PAGE") + ":",
noResults: this.$i18n.t("ID_NO_MATCHING_RECORDS")
},
selectable: {
mode: "single",
only: function (row) {
return true;
},
selectAllMode: "page",
programmatic: false,
},
requestFunction(data) {
return this.$parent.$parent.getCasesForVueTable(data);
},
},
pmDateFormat: "Y-m-d H:i:s",
clickCount: 0,
singleClickTimer: null,
statusTitle: {
"ON_TIME": this.$i18n.t("ID_IN_PROGRESS"),
"OVERDUE": this.$i18n.t("ID_TASK_OVERDUE"),
"DRAFT": this.$i18n.t("ID_IN_DRAFT"),
"PAUSED": this.$i18n.t("ID_PAUSED"),
"UNASSIGNED": this.$i18n.t("ID_UNASSIGNED")
}
};
},
mounted() {
this.initFilters();
},
watch: {},
computed: {
/**
* Build our ProcessMaker apiClient
*/
ProcessMaker() {
return window.ProcessMaker;
},
},
updated() {},
beforeCreate() {},
methods: {
/**
* Initialize filters
* updates the filters if there is an appUid parameter
*/
initFilters() {
let params,
filter = {refresh: true};
if(this.defaultOption) {
params = utils.getAllUrlParams(this.defaultOption);
if (params && params.openapplicationuid) {
filter = {
params: [
{
fieldId: "caseNumber",
filterVar: "caseNumber",
label: "",
options:[],
value: params.openapplicationuid,
autoShow: false
}
],
refresh: true
};
}
this.$emit("cleanDefaultOption");
}
this.onUpdateFilters(filter);
},
/**
* On row click event handler
* @param {object} event
*/
onRowClick(event) {
let self = this;
self.clickCount += 1;
if (self.clickCount === 1) {
self.singleClickTimer = setTimeout(function() {
self.clickCount = 0;
}, 400);
} else if (self.clickCount === 2) {
clearTimeout(self.singleClickTimer);
self.clickCount = 0;
self.claimCase(event.row);
}
},
/**
* Get cases unassigned data
*/
getCasesForVueTable(data) {
let that = this,
dt,
paged,
limit = data.limit,
start = data.page === 1 ? 0 : limit * (data.page - 1),
filters = {};
paged = start + "," + limit;
filters = {
paged: paged,
};
_.forIn(this.$parent.filters, function (item, key) {
filters[item.filterVar] = item.value;
});
return new Promise((resolutionFunc, rejectionFunc) => {
api.cases
.unassigned(filters)
.then((response) => {
dt = that.formatDataResponse(response.data.data);
resolutionFunc({
data: dt,
count: response.data.total,
});
})
.catch((e) => {
rejectionFunc(e);
});
});
},
/**
* Format Response API TODO to grid todo and columns
*/
formatDataResponse(response) {
let data = [];
_.forEach(response, (v) => {
data.push({
CASE_NUMBER: v.APP_NUMBER,
CASE_TITLE: v.DEL_TITLE,
PROCESS_NAME: v.PRO_TITLE,
TASK: [{
TITLE: v.TAS_TITLE,
CODE_COLOR: v.TAS_COLOR,
COLOR: v.TAS_COLOR_LABEL,
DELAYED_TITLE: v.TAS_STATUS === "OVERDUE" ?
this.$i18n.t("ID_DELAYED") + ":" : this.statusTitle[v.TAS_STATUS],
DELAYED_MSG: v.TAS_STATUS === "OVERDUE" ? v.DELAY : ""
}],
DUE_DATE: v.DEL_TASK_DUE_DATE_LABEL,
DELEGATION_DATE: v.DEL_DELEGATE_DATE_LABEL,
PRIORITY: v.DEL_PRIORITY_LABEL,
PRO_UID: v.PRO_UID,
TAS_UID: v.TAS_UID,
DEL_INDEX: v.DEL_INDEX,
APP_UID: v.APP_UID,
});
});
return data;
},
/**
* Claim case
*
* @param {object} item
*/
claimCase(item) {
let that = this;
api.cases.open(_.extend({ ACTION: "unassigned" }, item)).then(() => {
api.cases.cases_open(_.extend({ ACTION: "todo" }, item)).then(() => {
that.$refs["modal-claim-case"].data = item;
that.$refs["modal-claim-case"].show();
});
});
},
/**
* Open selected cases in the inbox
*
* @param {object} item
*/
openCase(item) {
this.$emit("onUpdateDataCase", {
APP_UID: item.APP_UID,
DEL_INDEX: item.DEL_INDEX,
PRO_UID: item.PRO_UID,
TAS_UID: item.TAS_UID,
ACTION: "todo"
});
this.$emit("onUpdatePage", "XCase");
},
/**
* Open case detail
*
* @param {object} item
*/
openCaseDetail(item) {
let that = this;
api.cases.open(_.extend({ ACTION: "todo" }, item)).then(() => {
api.cases.cases_open(_.extend({ ACTION: "todo" }, item)).then(() => {
that.$emit("onUpdateDataCase", {
APP_UID: item.APP_UID,
DEL_INDEX: item.DEL_INDEX,
PRO_UID: item.PRO_UID,
TAS_UID: item.TAS_UID,
APP_NUMBER: item.CASE_NUMBER,
});
that.$emit("onUpdatePage", "case-detail");
});
});
},
onRemoveFilter(data) {},
onUpdateFilters(data) {
if (data.params) {
this.$emit("onUpdateFilters", data.params);
}
if (data.refresh) {
this.$nextTick(() => {
this.$refs["vueTable"].getData();
});
}
},
/**
* update view in component
*/
updateView(){
this.$refs["vueTable"].getData();
}
},
};
</script>
<style>
.v-container-unassigned {
padding-top: 20px;
padding-bottom: 20px;
padding-left: 50px;
padding-right: 50px;
}
</style>

View File

@@ -0,0 +1,677 @@
<template>
<div id="v-unassigned" ref="v-unassigned" class="v-container-unassigned">
<button-fleft :data="newCase"></button-fleft>
<modal-new-request ref="newRequest"></modal-new-request>
<CasesFilter
:filters="filters"
:title="$t('ID_UNASSIGNED')"
:icon="icon"
@onRemoveFilter="onRemoveFilter"
@onUpdateFilters="onUpdateFilters"
/>
<multiview-header
:data="dataMultiviewHeader"
:dataSubtitle="dataSubtitle"
/>
<settings-popover :options="formatColumnSettings(options.headings)" target="pm-dr-column-settings" @onUpdateColumnSettings="onUpdateColumnSettings" :key="random+1" :selected="formatColumnSelected(columns)"/>
<v-server-table
v-if="typeView === 'GRID'"
:columns="columns"
:options="options"
ref="vueTable"
@row-click="onRowClick"
:key="random"
name="unassigned"
>
<div slot="detail" slot-scope="props">
<div class="btn-default" @click="openCaseDetail(props.row)">
<i class="fas fa-info-circle"></i>
</div>
</div>
<div slot="case_number" slot-scope="props">
{{ props.row.CASE_NUMBER }}
</div>
<div slot="case_title" slot-scope="props">
{{ props.row.CASE_TITLE }}
</div>
<div slot="process_name" slot-scope="props">
{{ props.row.PROCESS_NAME }}
</div>
<div slot="task" slot-scope="props">
<TaskCell :data="props.row.TASK" />
</div>
<div slot="send_by" slot-scope="props">
<CurrentUserCell :data="props.row.USER_DATA" />
</div>
<div slot="due_date" slot-scope="props">
{{ props.row.DUE_DATE }}
</div>
<div slot="delegation_date" slot-scope="props">
{{ props.row.DELEGATION_DATE }}
</div>
<div slot="priority" slot-scope="props">{{ props.row.PRIORITY }}</div>
<div slot="actions" slot-scope="props">
<div @click="updateDataEllipsis(props.row)">
<ellipsis :ref="`ellipsis-${props.row.TAS_UID}`" v-if="dataEllipsis" :data="dataEllipsis"> </ellipsis>
</div>
</div>
</v-server-table>
<VueCardView
v-if="typeView === 'CARD'"
:options="optionsVueList"
ref="vueCardView"
>
<div slot="actions" slot-scope="props">
<b-row>
<b-col sm="12">
<div class="v-pm-card-info" @click="openCaseDetail(props.item)">
<i class="fas fa-info-circle"></i>
</div>
</b-col>
<b-col sm="12">
<div class="ellipsis-container" @click="updateDataEllipsis(props.item)">
<ellipsis :ref="`ellipsis-${props.item.TAS_UID}`" v-if="dataEllipsis" :data="dataEllipsis"> </ellipsis>
</div>
</b-col>
</b-row>
</div>
<div slot="case_number" slot-scope="props" class="v-card-text">
<span class="v-card-text-highlight"
>{{ props["headings"][props.column] }} : {{ props["item"]["CASE_NUMBER"] }}</span
>
</div>
<div slot="case_title" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light"
>{{ props["item"]["CASE_TITLE"] }}
</span>
</div>
<div slot="process_name" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light"
>{{ props["item"]["PROCESS_NAME"] }}
</span>
</div>
<div slot="due_date" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light"
>{{ props["item"]["DUE_DATE"] }}
</span>
</div>
<div slot="delegation_date" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light"
>{{ props["item"]["DELEGATION_DATE"] }}
</span>
</div>
<div slot="task" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light">
<TaskCell :data="props.item.TASK" />
</span>
</div>
<div slot="send_by" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light">
<CurrentUserCell :data="props.item.USER_DATA" />
</span>
</div>
</VueCardView>
<VueListView
v-if="typeView === 'LIST'"
:options="optionsVueList"
ref="vueListView"
>
<div slot="actions" slot-scope="props">
<b-row>
<b-col sm="12">
<div class="v-pm-card-info" @click="openCaseDetail(props.item)">
<i class="fas fa-info-circle"></i>
</div>
</b-col>
<b-col sm="12">
<div class="ellipsis-container" @click="updateDataEllipsis(props.item)">
<ellipsis :ref="`ellipsis-${props.item.TAS_UID}`" v-if="dataEllipsis" :data="dataEllipsis"> </ellipsis>
</div>
</b-col>
</b-row>
</div>
<div slot="case_number" slot-scope="props" class="v-card-text">
<span class="v-card-text-highlight"
>{{ props["headings"][props.column] }} : {{ props["item"]["CASE_NUMBER"] }}</span
>
</div>
<div slot="case_title" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light"
>{{ props["item"]["CASE_TITLE"] }}
</span>
</div>
<div slot="process_name" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light"
>{{ props["item"]["PROCESS_NAME"] }}
</span>
</div>
<div slot="due_date" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light"
>{{ props["item"]["DUE_DATE"] }}
</span>
</div>
<div slot="delegation_date" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light"
>{{ props["item"]["DELEGATION_DATE"] }}
</span>
</div>
<div slot="task" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light">
<TaskCell :data="props.item.TASK" />
</span>
</div>
<div slot="send_by" slot-scope="props" class="v-card-text">
<span class="v-card-text-dark"
>{{ props["headings"][props.column] }} :</span
>
<span class="v-card-text-light">
<CurrentUserCell :data="props.item.USER_DATA" />
</span>
</div>
</VueListView>
<ModalClaimCase ref="modal-claim-case"></ModalClaimCase>
<ModalPauseCase ref="modal-pause-case"></ModalPauseCase>
</div>
</template>
<script>
import HeaderCounter from "../../components/home/HeaderCounter.vue";
import ButtonFleft from "../../components/home/ButtonFleft.vue";
import ModalNewRequest from "../ModalNewRequest.vue";
import TaskCell from "../../components/vuetable/TaskCell.vue";
import CasesFilter from "../../components/search/CasesFilter";
import ModalClaimCase from "../modal/ModalClaimCase.vue";
import api from "../../api/index";
import utils from "../../utils/utils";
import Ellipsis from '../../components/utils/ellipsis.vue';
import MultiviewHeader from "../../components/headers/MultiviewHeader.vue";
import VueCardView from "../../components/dataViews/vueCardView/VueCardView.vue";
import VueListView from "../../components/dataViews/vueListView/VueListView.vue";
import defaultMixins from "./defaultMixins";
import ModalPauseCase from '../modal/ModalPauseCase.vue';
import { Event } from 'vue-tables-2';
import CurrentUserCell from "../../components/vuetable/CurrentUserCell.vue";
export default {
name: "Unassigned",
mixins: [defaultMixins],
components: {
HeaderCounter,
ButtonFleft,
ModalNewRequest,
TaskCell,
ModalClaimCase,
CasesFilter,
Ellipsis,
MultiviewHeader,
VueCardView,
VueListView,
ModalPauseCase,
CurrentUserCell,
},
props: ["defaultOption", "settings"],
data() {
let that = this;
return {
columMap: {
case_number: "APP_NUMBER",
case_title: "DEL_TITLE",
process_name: "PRO_TITLE"
},
newCase: {
title: this.$i18n.t("ID_NEW_CASE"),
class: "btn-success",
onClick: () => {
this.$refs["newRequest"].show();
},
},
filters:
this.settings && this.settings.filters
? this.settings.filters
: {},
columns:
this.settings && this.settings.columns
? this.settings.columns
: [
"detail",
"case_number",
"case_title",
"process_name",
"task",
"send_by",
"due_date",
"delegation_date",
"priority",
"actions"
],
icon:"fas fa-users",
options: {
filterable: false,
headings: {
detail: this.$i18n.t("ID_DETAIL_CASE"),
case_number: this.$i18n.t("ID_MYCASE_NUMBER"),
case_title: this.$i18n.t("ID_CASE_TITLE"),
process_name: this.$i18n.t("ID_PROCESS_NAME"),
task: this.$i18n.t("ID_TASK"),
send_by: this.$i18n.t("ID_SEND_BY"),
due_date: this.$i18n.t("ID_DUE_DATE"),
delegation_date: this.$i18n.t("ID_DELEGATION_DATE"),
priority: this.$i18n.t("ID_PRIORITY"),
actions: ""
},
texts: {
count:this.$i18n.t("ID_SHOWING_FROM_RECORDS_COUNT"),
first: this.$i18n.t("ID_FIRST"),
last: this.$i18n.t("ID_LAST"),
filter: this.$i18n.t("ID_FILTER") + ":",
limit: this.$i18n.t("ID_RECORDS") + ":",
page: this.$i18n.t("ID_PAGE") + ":",
noResults: this.$i18n.t("ID_NO_MATCHING_RECORDS")
},
selectable: {
mode: "single",
only: function (row) {
return true;
},
selectAllMode: "page",
programmatic: false,
},
sortable: ['case_number'],
orderBy: this.settings && this.settings.orderBy ? this.settings.orderBy: {},
requestFunction(data) {
return this.$parent.$parent.getCasesForVueTable(data);
},
settings: {
"actions":{
class: "fas fa-cog",
id:"pm-dr-column-settings",
events:{
click(){
that.$root.$emit('bv::show::popover', 'pm-dr-column-settings')
}
}
}
},
},
pmDateFormat: "Y-m-d H:i:s",
clickCount: 0,
singleClickTimer: null,
statusTitle: {
"ON_TIME": this.$i18n.t("ID_IN_PROGRESS"),
"OVERDUE": this.$i18n.t("ID_TASK_OVERDUE"),
"DRAFT": this.$i18n.t("ID_IN_DRAFT"),
"PAUSED": this.$i18n.t("ID_PAUSED"),
"UNASSIGNED": this.$i18n.t("ID_UNASSIGNED")
},
dataEllipsis: {
buttons: {}
},
showEllipsis: false,
dataSubtitle: null
};
},
mounted() {
let that = this;
this.initFilters();
// define sort event
Event.$on('vue-tables.unassigned.sorted', function (data) {
that.$emit("updateSettings", {
data: data,
key: "orderBy",
parent: this.page,
type: "normal",
id: this.id
});
});
},
watch: {
columns: function (val) {
this.$emit("updateSettings", {
data: val,
key: "columns",
parent: this.page,
type: "normal",
id: this.id
});
},
filters: function (val) {
this.$emit("updateSettings", {
data: val,
key: "filters",
parent: this.page,
type: "normal",
id: this.id
});
},
},
computed: {
/**
* Build our ProcessMaker apiClient
*/
ProcessMaker() {
return window.ProcessMaker;
},
},
updated() {},
beforeCreate() {},
methods: {
/**
* Initialize filters
* updates the filters if there is an appUid parameter
*/
initFilters() {
let params,
filter = {refresh: true};
if(this.defaultOption) {
params = utils.getAllUrlParams(this.defaultOption);
if (params && params.openapplicationuid) {
filter = {
params: [
{
fieldId: "caseNumber",
filterVar: "caseNumber",
label: "",
options:[],
value: params.openapplicationuid,
autoShow: false
}
],
refresh: true
};
}
this.$emit("cleanDefaultOption");
}
this.onUpdateFilters(filter);
},
/**
* On row click event handler
* @param {object} event
*/
onRowClick(event) {
let self = this;
self.clickCount += 1;
if (self.clickCount === 1) {
self.singleClickTimer = setTimeout(function() {
self.clickCount = 0;
}, 400);
} else if (self.clickCount === 2) {
clearTimeout(self.singleClickTimer);
self.clickCount = 0;
self.claimCase(event.row);
}
},
/**
* Get cases unassigned data
*/
getCasesForVueTable(data) {
let that = this,
dt,
paged,
limit = data.limit,
start = data.page === 1 ? 0 : limit * (data.page - 1),
filters = {},
sort = "";
filters = {
limit: limit,
offset: start
};
_.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
.unassigned(filters)
.then((response) => {
dt = that.formatDataResponse(response.data.data);
resolutionFunc({
data: dt,
count: response.data.total,
});
})
.catch((e) => {
rejectionFunc(e);
});
});
},
/**
* Prepare sort string to be sended in the service
* @param {object} data
* @returns {string}
*/
prepareSortString(data){
let sort = "";
if (data.orderBy && this.columMap[data.orderBy]) {
sort = `${this.columMap[data.orderBy]},${data.ascending === 1 ? "ASC": "DESC"}`;
}
return sort;
},
/**
* Format Response API TODO to grid todo and columns
*/
formatDataResponse(response) {
let data = [];
_.forEach(response, (v) => {
data.push({
CASE_NUMBER: v.APP_NUMBER,
CASE_TITLE: v.DEL_TITLE,
PROCESS_NAME: v.PRO_TITLE,
TASK: [{
TITLE: v.TAS_TITLE,
CODE_COLOR: v.TAS_COLOR,
COLOR: v.TAS_COLOR_LABEL,
DELAYED_TITLE: v.TAS_STATUS === "OVERDUE" ?
this.$i18n.t("ID_DELAYED") + ":" : this.statusTitle[v.TAS_STATUS],
DELAYED_MSG: v.TAS_STATUS === "OVERDUE" ? v.DELAY : ""
}],
USER_DATA: this.formatUser(v.SEND_BY_INFO),
DUE_DATE: v.DEL_TASK_DUE_DATE_LABEL,
DELEGATION_DATE: v.DEL_DELEGATE_DATE_LABEL,
PRIORITY: v.DEL_PRIORITY_LABEL,
PRO_UID: v.PRO_UID,
TAS_UID: v.TAS_UID,
DEL_INDEX: v.DEL_INDEX,
APP_UID: v.APP_UID,
});
});
return data;
},
/**
* Set the format to show user's information
* @return {array} dataFormat
*/
formatUser(data) {
var dataFormat = [],
userDataFormat;
userDataFormat = utils.userNameDisplayFormat({
userName: data.user_tooltip.usr_firstname,
firstName: data.user_tooltip.usr_lastname,
lastName: data.user_tooltip.usr_username,
format: window.config.FORMATS.format || null
});
dataFormat.push({
USERNAME_DISPLAY_FORMAT: userDataFormat,
EMAIL: data.user_tooltip.usr_email,
POSITION: data.user_tooltip.usr_position,
AVATAR: userDataFormat !== "" ? window.config.SYS_SERVER_AJAX +
window.config.SYS_URI +
`users/users_ViewPhotoGrid?pUID=${data.user_tooltip.usr_id}` : "",
UNASSIGNED: userDataFormat !== "" ? true : false
});
return dataFormat;
},
/**
* Claim case
*
* @param {object} item
*/
claimCase(item) {
let that = this;
api.cases.open(_.extend({ ACTION: "unassigned" }, item)).then(() => {
api.cases.cases_open(_.extend({ ACTION: "todo" }, item)).then(() => {
that.$refs["modal-claim-case"].data = item;
that.$refs["modal-claim-case"].show();
});
});
},
/**
* Open selected cases in the inbox
*
* @param {object} item
*/
openCase(item) {
this.$emit("onUpdateDataCase", {
APP_UID: item.APP_UID,
DEL_INDEX: item.DEL_INDEX,
PRO_UID: item.PRO_UID,
TAS_UID: item.TAS_UID,
ACTION: "todo"
});
this.$emit("onUpdatePage", "XCase");
},
/**
* Open case detail
*
* @param {object} item
*/
openCaseDetail(item) {
let that = this;
api.cases.open(_.extend({ ACTION: "todo" }, item)).then(() => {
api.cases.cases_open(_.extend({ ACTION: "todo" }, item)).then(() => {
that.$emit("onUpdateDataCase", {
APP_UID: item.APP_UID,
DEL_INDEX: item.DEL_INDEX,
PRO_UID: item.PRO_UID,
TAS_UID: item.TAS_UID,
APP_NUMBER: item.CASE_NUMBER,
});
that.$emit("onUpdatePage", "case-detail");
});
});
},
onRemoveFilter(data) {},
onUpdateFilters(data) {
if (data.params) {
this.filters = data.params;
}
if (data.refresh) {
this.$nextTick(() => {
if (this.typeView === "GRID") {
this.$refs["vueTable"].getData();
}
if (this.typeView === "CARD") {
this.$refs["vueCardView"].getData();
}
if (this.typeView === "LIST") {
this.$refs["vueListView"].getData();
}
});
}
},
/**
* update view in component
*/
updateView(){
if (this.typeView === "GRID") {
this.$refs["vueTable"].getData();
}
if (this.typeView === "CARD") {
this.$refs["vueCardView"].getData();
}
if (this.typeView === "LIST") {
this.$refs["vueListView"].getData();
}
},
/**
* Show modal to pause a case
* @param {objec} data
*/
showModalPause(data) {
this.$refs["modal-pause-case"].data = data;
this.$refs["modal-pause-case"].show();
},
/**
* Show options in the ellipsis
* @param {object} data
*/
updateDataEllipsis(data) {
let that = this;
this.showEllipsis = !this.showEllipsis;
if (this.showEllipsis) {
this.dataEllipsis = {
buttons: {
note: {
name: "case note",
icon: "far fa-comments",
fn: function() {
that.openCaseDetail(data);
}
},
pause: {
name: "pause case",
icon: "far fa-pause-circle",
fn: function() {
that.showModalPause(data);
}
},
claim: {
name: "claim case",
icon: "fas fa-briefcase",
fn: function() {
that.claimCase(data);
}
}
}
}
}
},
},
};
</script>
<style>
.v-container-unassigned {
padding-top: 20px;
padding-bottom: 20px;
padding-left: 50px;
padding-right: 50px;
}
</style>

View File

@@ -0,0 +1,171 @@
import api from "../../api/index";
export default {
data() {
let that = this;
return {
typeView: "GRID",
random: 1,
dataMultiviewHeader: {
actions: [
{
id: "view-grid",
title: "Grid",
onClick(action) {
that.typeView = "GRID";
},
icon: "fas fa-table",
},
{
id: "view-list",
title: "List",
onClick(action) {
that.typeView = "LIST";
},
icon: "fas fa-list",
},
{
id: "view-card",
title: "Card",
onClick(action) {
that.typeView = "CARD";
},
icon: "fas fa-th",
},
],
},
optionsVueList: {
limit: 10,
dblClick:(event, item, options)=>{
this.openCase(item);
},
headings: {
case_number: this.$i18n.t("ID_MYCASE_NUMBER"),
case_title: this.$i18n.t("ID_CASE_TITLE"),
process_name: this.$i18n.t("ID_PROCESS_NAME"),
task: this.$i18n.t("ID_TASK"),
send_by: this.$i18n.t("ID_SEND_BY"),
current_user: this.$i18n.t("ID_CURRENT_USER"),
due_date: this.$i18n.t("ID_DUE_DATE"),
delegation_date: this.$i18n.t("ID_DELEGATION_DATE"),
priority: this.$i18n.t("ID_PRIORITY")
},
columns: [
"case_number",
"case_title",
"process_name",
"due_date",
"delegation_date",
"priority",
"task",
"send_by",
],
requestFunction(data) {
return that.getCases(data);
},
requestFunctionViewMore(data) {
return that.getCasesViewMore(data);
}
}
}
},
created: function () {
},
methods: {
/**
* Get cases for Vue Card View
*/
getCases(data) {
let that = this,
dt,
filters = {};
_.forIn(this.filters, function (item, key) {
filters[item.filterVar] = item.value;
});
return new Promise((resolutionFunc, rejectionFunc) => {
api.cases
.unassigned(filters)
.then((response) => {
dt = that.formatDataResponse(response.data.data);
resolutionFunc({
data: dt,
count: response.data.total,
});
})
.catch((e) => {
rejectionFunc(e);
});
});
},
/**
* Get cases for Vue Card View
*/
getCasesViewMore(data) {
let that = this,
dt,
paged,
limit = data.limit,
start = data.page === 1 ? 0 : limit * (data.page - 1),
filters = {};
filters = {
limit: limit,
offset: start
};
_.forIn(this.filters, function (item, key) {
if (filters && item.value) {
filters[item.filterVar] = item.value;
}
});
return new Promise((resolutionFunc, rejectionFunc) => {
api.cases
.unassigned(filters)
.then((response) => {
dt = that.formatDataResponse(response.data.data);
resolutionFunc({
data: dt,
count: response.data.total,
});
})
.catch((e) => {
rejectionFunc(e);
});
});
},
/**
* Format columns for custom columns
* @param {*} headings
* @returns
*/
formatColumnSettings(headings) {
let res=[];
_.forEach(headings, function(value, key) {
if(key != "actions"){
res.push({value,key});
}
});
return res;
},
/**
* Formating the columns selected
* @param {*} columns
* @returns
*/
formatColumnSelected(columns) {
let cols = _.clone(columns);
cols.pop();
return cols;
},
/**
* Event handler when update the settings columns
* @param {*} columns
*/
onUpdateColumnSettings(columns) {
let cols = columns;
if(_.findIndex(cols, 'actions') == -1){
cols.push("actions");
}
this.columns = cols;
this.random = _.random(0, 10000000000);
}
}
}

View File

@@ -3,24 +3,39 @@ import VueRouter from "vue-router";
import VueSidebarMenu from "vue-sidebar-menu";
import VueI18n from 'vue-i18n';
import { BootstrapVue, BootstrapVueIcons } from 'bootstrap-vue';
import { ServerTable, Event, ClientTable} from 'vue-tables-2';
import { ServerTable, Event, ClientTable } from 'vue-tables-2';
import VtTableHeadingCustom from './../components/vuetable/extends/VtTableHeadingCustom';
import VtSortControl from './../components/vuetable/extends/VtSortControl';
import SettingsPopover from "../components/vuetable/SettingsPopover.vue";
import Sortable from 'sortablejs';
import "@fortawesome/fontawesome-free/css/all.css";
import "@fortawesome/fontawesome-free/js/all.js";
import 'bootstrap/dist/css/bootstrap-grid.css';
import 'bootstrap/dist/css/bootstrap.min.css'
import 'bootstrap-vue/dist/bootstrap-vue.css';
import VueApexCharts from 'vue-apexcharts'
import 'bootstrap-vue/dist/bootstrap-vue.css'
import Home from "./Home";
Vue.use(VueApexCharts);
Vue.use(VueRouter);
Vue.use(VueSidebarMenu);
Vue.use(BootstrapVue);
Vue.use(BootstrapVueIcons);
Vue.use(VueI18n);
Vue.use(ServerTable, {}, false, 'bootstrap3', {});
Vue.use(ServerTable, {}, false, 'bootstrap3', {
tableHeading: VtTableHeadingCustom,
sortControl: VtSortControl
});
Vue.use(ClientTable, {}, false, 'bootstrap3', {});
Vue.component('settings-popover', SettingsPopover);
Vue.component('apexchart', VueApexCharts);
window.ProcessMaker = {
apiClient: require('axios')
};
window.ProcessMaker.pluginBase = "/sysworkflow/en/neoclassic/viena/index.php";
window.ProcessMaker.apiClient.defaults.baseURL = '/sysworkflow/en/neoclassic/viena/index.php/api/';
window.ProcessMaker.SYS_SYS = "workflow";

View File

@@ -30,6 +30,8 @@
<script>
import api from "./../../api/index";
import eventBus from "../EventBus/eventBus";
export default {
name: "ModalClaimCase",
components: {},
@@ -57,14 +59,25 @@ export default {
api.cases.claim(this.data).then((response) => {
if (response.status === 200) {
that.$refs["modal-claim-case"].hide();
that.$parent.$emit("onUpdateDataCase", {
that.$parent.$refs['ellipsis-' + that.data.TAS_UID].hideActionButtons()
if (that.$parent.$refs["vueTable"] !== undefined) {
that.$parent.$refs["vueTable"].getData();
}
if (that.$parent.$refs["vueListView"] !== undefined) {
that.$parent.$refs["vueListView"].getData();
}
if (that.$parent.$refs["vueCardView"] !== undefined) {
that.$parent.$refs["vueCardView"].getData();
}
//TODO Trigger onUpdateDataCase
eventBus.$emit("home-update-datacase", {
APP_UID: this.data.APP_UID,
DEL_INDEX: this.data.DEL_INDEX,
PRO_UID: this.data.PRO_UID,
TAS_UID: this.data.TAS_UID,
ACTION: "todo",
});
that.$parent.$emit("onUpdatePage", "XCase");
eventBus.$emit("home-update-page", "XCase");
}
});
},

View File

@@ -93,20 +93,18 @@ export default {
})
)
.then((response) => {
if (
response.data.success === "success" &&
response.data.message == ""
) {
if (response.status === 200) {
that.attachDocuments = false;
that.dataAttachedDocuments.items = [];
that.getCasesNotes();
this.$refs["modal-comments"].hide();
this.$emit("postNotes");
} else {
that.showAlert(response.data.message, "danger");
that.dataAttachedDocuments.items = [];
this.$emit("postNotes");
}
});
})
.catch((error) => {
that.showAlert(error.response.data.error.message, "danger");
that.dataAttachedDocuments.items = [];
})
},
};
},

View File

@@ -0,0 +1,171 @@
<template>
<div>
<b-modal
ref="modal-pause-case"
hide-footer
size="lg"
>
<template v-slot:modal-title>
{{ $t('ID_PAUSE_CASE') }}
<i class="far fa-pause-circle"></i>
</template>
<b-container fluid>
<b-row class="my-1">
<b-col sm="3">
<label for="pauseDate">{{ $t('ID_PAUSE_DATE') }}</label>
</b-col>
<b-col sm="5">
<b-form-datepicker
disabled
id="pauseDate"
class="mb-2"
v-model="pauseData.pauseDate"
:locale="locale"
:date-format-options="{ year: 'numeric', month: 'numeric', day: 'numeric' }"
></b-form-datepicker>
</b-col>
<b-col sm="4">
<input type="time" id="pauseTime" v-model="pauseData.pauseTime" class="form-control" disabled>
</b-col>
</b-row>
<b-row class="my-1">
<b-col sm="3">
<label for="unpauseDate">{{ $t('ID_UNPAUSE_DATE') }}</label>
</b-col>
<b-col sm="5">
<b-form-datepicker
id="unpauseDate"
class="mb-2"
v-model="pauseData.unpauseDate"
:locale="locale"
:min="minDate"
:date-format-options="{ year: 'numeric', month: 'numeric', day: 'numeric' }"
></b-form-datepicker>
</b-col>
<b-col sm="4">
<input type="time" v-model="pauseData.unpauseTime" id="unpauseTime" class="form-control">
</b-col>
</b-row>
<b-row class="my-1">
<b-col sm="3">
<label for="reasonPause">{{ $t('ID_REASON_PAUSE') }}</label>
</b-col>
<b-col sm="9">
<b-form-textarea
id="reasonPause"
v-model="pauseData.reasonPause"
rows="3"
max-rows="6"
></b-form-textarea>
</b-col>
</b-row>
<b-row>
<b-col sm="3">
<label for="notifyUser">{{ $t('ID_NOTIFY_USERS_CASE') }}</label>
</b-col>
<b-col sm="8">
<b-form-checkbox v-model="pauseData.nofitfyUser" id="notifyUser" name="notifyUser" switch>
</b-form-checkbox>
</b-col>
</b-row>
</b-container>
<div class="modal-footer">
<div class="float-right">
<b-button
variant="danger"
data-dismiss="modal"
@click="cancel"
>
{{ $t("ID_CANCEL") }}
</b-button>
<b-button
variant="success"
@click="pauseCase"
>
{{ $t("ID_PAUSE") }}
</b-button>
</div>
</div>
</b-modal>
</div>
</template>
<script>
import api from "./../../api/index";
export default {
name: "ModalPauseCase",
components: {},
props: {},
mounted() {},
data() {
return {
data: null,
locale: 'en-US',
pauseData: {
unpauseDate: '',
unpauseTime: '',
reasonPause: '',
nofitfyUser: '',
pauseDate: '',
pauseTime: ''
},
minDate: '',
};
},
methods: {
classBtn(cls) {
return "btn v-btn-request " + cls;
},
show() {
this.setDateTime();
this.$refs["modal-pause-case"].show();
},
cancel() {
this.$refs["modal-pause-case"].hide();
},
/**
* Set DateTime with current time as default
*/
setDateTime() {
var now = new Date(),
nextDay = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1),
today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
this.minDate = nextDay;
this.pauseData.pauseDate = today;
this.pauseData.pauseTime = now.getHours() + ":" + now.getMinutes();
},
/**
* Pause the case
*/
pauseCase() {
let that = this;
this.data.unpausedDate = this.pauseData.unpauseDate;
this.data.unpausedTime = this.pauseData.unpauseTime;
this.data.nofitfyUser = this.pauseData.nofitfyUser;
this.data.reasonPause = this.pauseData.reasonPause;
api.cases.pauseCase(this.data).then((response) => {
if (response.statusText == "OK") {
that.$refs["modal-pause-case"].hide();
that.$parent.$refs['ellipsis-' + that.data.TAS_UID].hideActionButtons()
if (that.$parent.$refs["vueTable"] !== undefined) {
that.$parent.$refs["vueTable"].getData();
}
if (that.$parent.$refs["vueListView"] !== undefined) {
that.$parent.$refs["vueListView"].getData();
}
if (that.$parent.$refs["vueCardView"] !== undefined) {
that.$parent.$refs["vueCardView"].getData();
}
}
});
},
},
};
</script>
<style>
</style>

View File

@@ -0,0 +1,152 @@
<template>
<div>
<b-modal
ref="modal-reassign-case"
hide-footer
size="lg"
>
<template v-slot:modal-title>
{{ $t('ID_REASSIGN_CASE') }}
<i class="fas fa-undo"></i>
</template>
<b-container fluid>
<b-row class="my-1">
<b-col sm="3">
<label for="selectUser">{{ $t('ID_SELECT_USER') }}</label>
</b-col>
<b-col sm="9">
<b-form-select v-model="userSelected" :options="users"></b-form-select>
</b-col>
</b-row>
<b-row class="my-1">
<b-col sm="3">
<label for="reasonReassign">{{ $t('ID_REASON_REASSIGN') }}</label>
</b-col>
<b-col sm="9">
<b-form-textarea
id="reasonReassign"
v-model="reasonReassign"
rows="3"
max-rows="6"
></b-form-textarea>
</b-col>
</b-row>
<b-row class="my-1">
<b-col sm="3">
<label for="notifyUser">{{ $t('ID_NOTIFY_USERS_CASE') }}</label>
</b-col>
<b-col sm="9">
<b-form-checkbox v-model="notifyUser" id="notifyUser" name="notifyUser" switch>
</b-form-checkbox>
</b-col>
</b-row>
</b-container>
<div class="modal-footer">
<div class="float-right">
<b-button
variant="danger"
data-dismiss="modal"
@click="cancel"
>
{{ $t("ID_CANCEL") }}
</b-button>
<b-button
variant="success"
@click="reassignCase"
>
{{ $t("ID_PAUSE") }}
</b-button>
</div>
</div>
</b-modal>
</div>
</template>
<script>
import api from "./../../api/index";
import utils from "../../utils/utils";
export default {
name: "ModalPauseCase",
components: {},
props: {},
mounted() {},
data() {
return {
data: null,
locale: 'en-US',
users: [],
reasonReassign: null,
userSelected: null,
notifyUser: false
};
},
methods: {
classBtn(cls) {
return "btn v-btn-request " + cls;
},
/**
* Show modal
*/
show() {
this.getUsersReassign();
this.$refs["modal-reassign-case"].show();
},
/**
* Button cancel
*/
cancel() {
this.$refs["modal-reassign-case"].hide();
},
/**
* Service to get user reassign
*/
getUsersReassign() {
let that = this;
api.cases.getUserReassign(this.data).then((response) => {
var users = response.data.data,
i;
if (response.statusText == "OK") {
for (i = 0; i < users.length; i += 1) {
that.users.push({
value: users[i].USR_UID,
text: utils.userNameDisplayFormat({
userName: users[i].USR_USERNAME || "",
firstName: users[i].USR_FIRSTNAME || "",
lastName: users[i].USR_LASTNAME || "",
format: window.config.FORMATS.format || null
})
});
}
}
});
},
/**
* Service reassign case
*/
reassignCase() {
let that = this;
this.data.userSelected = this.userSelected;
this.data.reasonReassign = this.reasonReassign;
this.notifyUser = this.notifyUser;
api.cases.reassingCase(this.data).then((response) => {
if (response.statusText == "OK") {
that.$refs["modal-reassign-case"].hide();
that.$parent.$refs['ellipsis-' + that.data.TAS_UID].hideActionButtons()
if (that.$parent.$refs["vueTable"] !== undefined) {
that.$parent.$refs["vueTable"].getData();
}
if (that.$parent.$refs["vueListView"] !== undefined) {
that.$parent.$refs["vueListView"].getData();
}
if (that.$parent.$refs["vueCardView"] !== undefined) {
that.$parent.$refs["vueCardView"].getData();
}
}
});
},
},
};
</script>

View File

@@ -55,7 +55,16 @@ export default {
api.cases.unpause(this.data).then((response) => {
if (response.statusText == "OK") {
that.$refs["modal-unpause-case"].hide();
that.$parent.$refs["vueTable"].getData();
that.$parent.$refs['ellipsis-' + that.data.TAS_UID].hideActionButtons()
if (that.$parent.$refs["vueTable"] !== undefined) {
that.$parent.$refs["vueTable"].getData();
}
if (that.$parent.$refs["vueListView"] !== undefined) {
that.$parent.$refs["vueListView"].getData();
}
if (that.$parent.$refs["vueCardView"] !== undefined) {
that.$parent.$refs["vueCardView"].getData();
}
}
});
},

Some files were not shown because too many files have changed in this diff Show More