Discover: sidebarFilter Funnel to be decided.
This commit is contained in:
@@ -83,7 +83,7 @@
|
|||||||
|
|
||||||
<!-- Button -->
|
<!-- Button -->
|
||||||
<div class="float-right space-x-4 px-4 py-2">
|
<div class="float-right space-x-4 px-4 py-2">
|
||||||
<button class="btn btn-sm btn-neutral" @click="reset">Reset</button>
|
<button class="btn btn-sm btn-neutral" @click="reset">Clear</button>
|
||||||
<button class="btn btn-sm btn-neutral" @click="submit">Apply</button>
|
<button class="btn btn-sm btn-neutral" @click="submit">Apply</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -94,7 +94,55 @@
|
|||||||
|
|
||||||
|
|
||||||
<!-- header: funnel -->
|
<!-- header: funnel -->
|
||||||
<div v-if="tab === 'funnel'">temporaryData:{{ temporaryData }}</div>
|
<div v-if="tab === 'funnel'" class="bg-neutral-10 w-full h-full">
|
||||||
|
<div class="h-[calc(100%_-_58px)] border-b border-neutral-300 mb-2">
|
||||||
|
<div v-if="temporaryData.length === 0" class="h-full flex justify-center items-center">
|
||||||
|
<span class="text-neutral-500">No Filter.</span>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
temporaryData:{{ temporaryData }}
|
||||||
|
<Timeline :value="events">
|
||||||
|
<template #content="slotProps">
|
||||||
|
{{ slotProps.item.status }}
|
||||||
|
</template>
|
||||||
|
</Timeline>
|
||||||
|
|
||||||
|
<!-- <Timeline :value="events" align="alternate" class="customized-timeline">
|
||||||
|
<template #marker="slotProps">
|
||||||
|
<span class="!flex !w-2rem !h-2rem !align-items-center !justify-content-center !text-white !border-circle !z-1 !shadow-1" :style="{ backgroundColor: slotProps.item.color }">
|
||||||
|
<i :class="slotProps.item.icon"></i>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<template #content="slotProps">
|
||||||
|
{{ slotProps.item.status }}
|
||||||
|
<Card>
|
||||||
|
<template #title>
|
||||||
|
{{ slotProps.item.status }}
|
||||||
|
</template>
|
||||||
|
<template #subtitle>
|
||||||
|
{{ slotProps.item.date }}
|
||||||
|
</template>
|
||||||
|
<template #content>
|
||||||
|
<img v-if="slotProps.item.image" :src="`https://primefaces.org/cdn/primevue/images/product/${slotProps.item.image}`" :alt="slotProps.item.name" width="200" class="shadow-1" />
|
||||||
|
<p>
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Inventore sed consequuntur error repudiandae numquam deserunt quisquam repellat libero asperiores earum nam nobis, culpa ratione quam perferendis esse, cupiditate
|
||||||
|
neque quas!
|
||||||
|
</p>
|
||||||
|
<Button label="Read more" text></Button>
|
||||||
|
</template>
|
||||||
|
</Card>
|
||||||
|
</template>
|
||||||
|
</Timeline> -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Button -->
|
||||||
|
<div class="">
|
||||||
|
<div class="float-right space-x-4 px-4 py-2">
|
||||||
|
<button class="btn btn-sm btn-neutral" @click="deleteAll">Delete All</button>
|
||||||
|
<button class="btn btn-sm btn-neutral" @click="submitAll">Apply All</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</Sidebar>
|
</Sidebar>
|
||||||
</template>
|
</template>
|
||||||
@@ -102,6 +150,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import LoadingStore from '@/stores/loading.js';
|
import LoadingStore from '@/stores/loading.js';
|
||||||
|
import AllMapDataStore from '@/stores/allMapData.js';
|
||||||
import ActOccCase from '@/components/Discover/table/actOccCase.vue';
|
import ActOccCase from '@/components/Discover/table/actOccCase.vue';
|
||||||
import ActOcc from '@/components/Discover/table/actOcc.vue';
|
import ActOcc from '@/components/Discover/table/actOcc.vue';
|
||||||
import ActAndSeq from '@/components/Discover/table/actAndSeq.vue';
|
import ActAndSeq from '@/components/Discover/table/actAndSeq.vue';
|
||||||
@@ -135,11 +184,20 @@ export default {
|
|||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const loadingStore = LoadingStore();
|
const loadingStore = LoadingStore();
|
||||||
|
const allMapDataStore = AllMapDataStore();
|
||||||
const { isLoading } = storeToRefs(loadingStore);
|
const { isLoading } = storeToRefs(loadingStore);
|
||||||
return { isLoading }
|
const { tempFilterId } = storeToRefs(allMapDataStore);
|
||||||
|
|
||||||
|
return { isLoading, tempFilterId, allMapDataStore }
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
events: [
|
||||||
|
{ status: 'Ordered', date: '15/10/2020 10:30', icon: 'pi pi-shopping-cart', color: '#9C27B0'},
|
||||||
|
{ status: 'Processing', date: '15/10/2020 14:00', icon: 'pi pi-cog', color: '#673AB7' },
|
||||||
|
{ status: 'Shipped', date: '15/10/2020 16:15', icon: 'pi pi-shopping-cart', color: '#FF9800' },
|
||||||
|
{ status: 'Delivered', date: '16/10/2020 10:00', icon: 'pi pi-check', color: '#607D8B' }
|
||||||
|
],
|
||||||
selectFilter: {
|
selectFilter: {
|
||||||
'Filter Type': ['Sequence', 'Attributes', 'Trace', 'Timeframes'],
|
'Filter Type': ['Sequence', 'Attributes', 'Trace', 'Timeframes'],
|
||||||
'Activity Sequence':['Have activity(s)', 'Start activity & end activity', 'Sequence'],
|
'Activity Sequence':['Have activity(s)', 'Start activity & end activity', 'Sequence'],
|
||||||
@@ -171,7 +229,7 @@ export default {
|
|||||||
isEndSelected: null,
|
isEndSelected: null,
|
||||||
isActAllTask: true,
|
isActAllTask: true,
|
||||||
rowData: [],
|
rowData: [],
|
||||||
temporaryData: null,
|
temporaryData: [],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
@@ -324,7 +382,7 @@ export default {
|
|||||||
/**
|
/**
|
||||||
* 清空選項
|
* 清空選項
|
||||||
*/
|
*/
|
||||||
reset() {
|
reset(massage) {
|
||||||
this.selectFilterTask = null;
|
this.selectFilterTask = null;
|
||||||
this.selectFilterStart = null;
|
this.selectFilterStart = null;
|
||||||
this.selectFilterEnd = null;
|
this.selectFilterEnd = null;
|
||||||
@@ -334,9 +392,9 @@ export default {
|
|||||||
this.isStartSelected = null;
|
this.isStartSelected = null;
|
||||||
this.isEndSelected = null;
|
this.isEndSelected = null;
|
||||||
this.isActAllTask = true;
|
this.isActAllTask = true;
|
||||||
this.$toast.success('Reset Success.');
|
massage ? this.$toast.success('Reset Success.') : null;
|
||||||
},
|
},
|
||||||
// 發送選取的資料
|
// header:Filter 發送選取的資料
|
||||||
submit(){
|
submit(){
|
||||||
let data;
|
let data;
|
||||||
let sele = this.selectValue;
|
let sele = this.selectValue;
|
||||||
@@ -346,7 +404,7 @@ export default {
|
|||||||
// 若陣列為空,則跳出警告訊息
|
// 若陣列為空,則跳出警告訊息
|
||||||
if(sele[0] === 'Sequence'){
|
if(sele[0] === 'Sequence'){
|
||||||
if(sele[1] === 'Have activity(s)'){ // Activity Sequence 選 Have activity(s) 的行為
|
if(sele[1] === 'Have activity(s)'){ // Activity Sequence 選 Have activity(s) 的行為
|
||||||
if(this.selectFilterTask === null || this.selectFilterTask.length === 0) return this.$toast.error('未選擇');
|
if(this.selectFilterTask === null || this.selectFilterTask.length === 0) return this.$toast.error('Not selected');
|
||||||
else {
|
else {
|
||||||
// 將多選的 task 拆成一包包 obj
|
// 將多選的 task 拆成一包包 obj
|
||||||
data = this.selectFilterTask.map(task => {
|
data = this.selectFilterTask.map(task => {
|
||||||
@@ -359,7 +417,7 @@ export default {
|
|||||||
};
|
};
|
||||||
}else if(sele[1] === 'Start activity & end activity') { // Activity Sequence 選 Start activity & end activity 的行為
|
}else if(sele[1] === 'Start activity & end activity') { // Activity Sequence 選 Start activity & end activity 的行為
|
||||||
if(sele[2] === 'Start') {
|
if(sele[2] === 'Start') {
|
||||||
if(this.selectFilterStart === null || this.selectFilterStart.length === 0) return this.$toast.error('未選擇');
|
if(this.selectFilterStart === null || this.selectFilterStart.length === 0) return this.$toast.error('Not selected');
|
||||||
else {
|
else {
|
||||||
data = {
|
data = {
|
||||||
type: 'starts-with',
|
type: 'starts-with',
|
||||||
@@ -368,7 +426,7 @@ export default {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}else if(sele[2] === 'End') {
|
}else if(sele[2] === 'End') {
|
||||||
if(this.selectFilterEnd === null || this.selectFilterEnd.length === 0) return this.$toast.error('未選擇');
|
if(this.selectFilterEnd === null || this.selectFilterEnd.length === 0) return this.$toast.error('Not selected');
|
||||||
else {
|
else {
|
||||||
data = {
|
data = {
|
||||||
type: 'starts-with',
|
type: 'starts-with',
|
||||||
@@ -377,7 +435,7 @@ export default {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}else if(sele[2] === 'Start & End') {
|
}else if(sele[2] === 'Start & End') {
|
||||||
if(this.selectFilterStartToEnd === null || this.selectFilterStartToEnd.length === 0 || this.selectFilterEndToStart === null || this.selectFilterEndToStart.length === 0 ) return this.$toast.error('未選擇');
|
if(this.selectFilterStartToEnd === null || this.selectFilterStartToEnd.length === 0 || this.selectFilterEndToStart === null || this.selectFilterEndToStart.length === 0 ) return this.$toast.error('Both Start and End must be selected.');
|
||||||
else {
|
else {
|
||||||
data = {
|
data = {
|
||||||
type: 'start-end',
|
type: 'start-end',
|
||||||
@@ -388,31 +446,53 @@ export default {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}else if(sele[1] === 'Sequence'){ // Activity Sequence 選 Sequence 的行為
|
}else if(sele[1] === 'Sequence'){ // Activity Sequence 選 Sequence 的行為
|
||||||
if(this.listSeq.length < 2) return this.$toast.error('未選擇');
|
if(this.listSeq.length < 2) return this.$toast.error('Select two or more.');
|
||||||
else {
|
else {
|
||||||
data = {
|
data = {
|
||||||
type: sele[3] === 'Directly follows' ? 'directly-follows' : 'eventually-follows',
|
type: sele[3] === 'Directly follows' ? 'directly-follows' : 'eventually-follows',
|
||||||
task: this.listSeq.map(task => task.label),
|
task_seq: this.listSeq.map(task => task.label),
|
||||||
is_exclude: isExclude,
|
is_exclude: isExclude,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 將資料指向 Vue dat 雙向綁定
|
// 將資料指向 Vue data 雙向綁定
|
||||||
this.temporaryData = data;
|
const postData = Array.isArray(data) ? data : [data];
|
||||||
|
this.temporaryData.push(...postData);
|
||||||
// 結束後要清空資料
|
// 結束後要清空資料
|
||||||
this.reset();
|
this.reset(false);
|
||||||
// 發送時,isLoading
|
// 發送時,isLoading
|
||||||
this.isLoading = true;
|
this.isLoading = true;
|
||||||
// 結束後,要跳出傳送成功的訊息
|
// 結束後,要跳出傳送成功的訊息
|
||||||
// 跳轉 this.tab = 'funnel';
|
// 跳轉 this.tab = 'funnel';
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
this.$toast.success('Filter Success');
|
this.$toast.success('Filter Success. Click on Funnel to view the configuration result.');
|
||||||
this.tab = 'funnel';
|
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
// 快速檢查每一 filter 規則是否為空集合
|
||||||
|
let logId = this.$route.params.logId;
|
||||||
|
this.axios.post(`/api/filters/has-result?log_id=${logId}`, postData)
|
||||||
|
.then(res=>{
|
||||||
|
res.data.result ? null : this.$toast.warning('No result.');
|
||||||
|
}).catch(err=>{
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
// header:Funnel 刪除全部的 Funnel
|
||||||
|
deleteAll() {
|
||||||
|
this.temporaryData = [];
|
||||||
|
this.$toast.success('All deleted.');
|
||||||
|
},
|
||||||
|
// header:Funnel 發送暫存的選取資料
|
||||||
|
submitAll() {
|
||||||
|
let logId = this.$route.params.logId;
|
||||||
|
this.axios.post(`/api/temp-filters?log_id=${logId}`, this.temporaryData)
|
||||||
|
.then(res=>{
|
||||||
|
console.log(res);
|
||||||
|
this.tempFilterId = res.data.id;
|
||||||
|
}).catch(err=>{
|
||||||
|
console.log(err);
|
||||||
|
})
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@@ -422,4 +502,14 @@ export default {
|
|||||||
#searchFiles::-webkit-search-cancel-button{
|
#searchFiles::-webkit-search-cancel-button{
|
||||||
appearance: none;
|
appearance: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TimeLine */
|
||||||
|
:deep(.p-timeline-event-marker) {
|
||||||
|
@apply !bg-primary !border-primary !h-2 !w-2
|
||||||
|
/* @apply !bg-primary !border-primary */
|
||||||
|
}
|
||||||
|
:deep(.p-timeline-event-connector) {
|
||||||
|
@apply !bg-primary my-2 !w-[1px]
|
||||||
|
/* @apply !bg-primary my-2 */
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="w-full h-full fixed inset-0 m-auto flex justify-center items-center bg-gradient-to-tr from-neutral-500/50 to-neutral-900/50 z-20">
|
<div class="w-full h-full fixed inset-0 m-auto flex justify-center items-center bg-gradient-to-tr from-neutral-500/50 to-neutral-900/50 z-50">
|
||||||
<span class="loader block"></span>
|
<span class="loader block"></span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import ColumnGroup from 'primevue/columngroup'; // optional
|
|||||||
import Row from 'primevue/row'; // optional
|
import Row from 'primevue/row'; // optional
|
||||||
import RadioButton from 'primevue/radiobutton';
|
import RadioButton from 'primevue/radiobutton';
|
||||||
import PickList from 'primevue/picklist';
|
import PickList from 'primevue/picklist';
|
||||||
|
import Timeline from 'primevue/timeline';
|
||||||
|
|
||||||
const emitter = mitt();
|
const emitter = mitt();
|
||||||
const app = createApp(App);
|
const app = createApp(App);
|
||||||
@@ -60,6 +61,7 @@ app.use(pinia);
|
|||||||
app.use(router);
|
app.use(router);
|
||||||
app.use(VueAxios, axios);
|
app.use(VueAxios, axios);
|
||||||
app.use(ToastPlugin, { // use `this.$toast` in Vue.js
|
app.use(ToastPlugin, { // use `this.$toast` in Vue.js
|
||||||
|
position: 'bottom',
|
||||||
duration: 5000,
|
duration: 5000,
|
||||||
});
|
});
|
||||||
app.use(PrimeVue);
|
app.use(PrimeVue);
|
||||||
@@ -76,6 +78,7 @@ app.component('ColumnGroup', ColumnGroup);
|
|||||||
app.component('Row', Row);
|
app.component('Row', Row);
|
||||||
app.component('RadioButton', RadioButton);
|
app.component('RadioButton', RadioButton);
|
||||||
app.component('PickList', PickList);
|
app.component('PickList', PickList);
|
||||||
|
app.component('Timeline', Timeline);
|
||||||
app.component('Draggable', draggable); // 拖曳
|
app.component('Draggable', draggable); // 拖曳
|
||||||
|
|
||||||
app.mount("#app");
|
app.mount("#app");
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ export default defineStore('allMapDataStore', {
|
|||||||
state: () => ({
|
state: () => ({
|
||||||
logId: null,
|
logId: null,
|
||||||
traceId: 1,
|
traceId: 1,
|
||||||
|
tempFilterId: null,
|
||||||
allProcessMap: {},
|
allProcessMap: {},
|
||||||
allBpmn: {},
|
allBpmn: {},
|
||||||
allStats: {},
|
allStats: {},
|
||||||
@@ -75,7 +76,11 @@ export default defineStore('allMapDataStore', {
|
|||||||
*/
|
*/
|
||||||
async getAllMapData() {
|
async getAllMapData() {
|
||||||
let logId = this.logId;
|
let logId = this.logId;
|
||||||
const api = `/api/logs/${logId}/discover`;
|
let tempFilterId = this.tempFilterId;
|
||||||
|
let api = tempFilterId !== null ? `/api/temp-filters/${tempFilterId}/discover` : `/api/logs/${logId}/discover`;
|
||||||
|
console.log(tempFilterId);
|
||||||
|
console.log(logId);
|
||||||
|
// const api = `/api/logs/${logId}/discover`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await this.$axios.get(api);
|
const response = await this.$axios.get(api);
|
||||||
|
|||||||
Reference in New Issue
Block a user