Map Attributes: Apply, Clear done.

This commit is contained in:
chiayin
2023-10-31 15:29:18 +08:00
parent fdba0abc37
commit 2ac112dbbd
4 changed files with 215 additions and 54 deletions

View File

@@ -11,7 +11,7 @@
<div class="basis-1/3 bg-neutral-10 border border-neutral-300 rounded-xl px-4 pb-4 w-full h-full relative text-sm"> <div class="basis-1/3 bg-neutral-10 border border-neutral-300 rounded-xl px-4 pb-4 w-full h-full relative text-sm">
<p class="h2 my-2">Attribute Name ({{ attTotal }})</p> <p class="h2 my-2">Attribute Name ({{ attTotal }})</p>
<div class="overflow-y-auto overflow-x-auto scrollbar -mx-2 h-[calc(100%_-_56px)]"> <div class="overflow-y-auto overflow-x-auto scrollbar -mx-2 h-[calc(100%_-_56px)]">
<DataTable v-model:selection="selectedAttName" :value="filterAttrs" dataKey="key" breakpoint="0" :tableClass="tableClass" @row-select="onRowSelect"> <DataTable v-model:selection="selectedAttName" :value="filterAttrs" dataKey="key" breakpoint="0" :tableClass="tableClass" @row-select="switchAttNameRadio">
<Column selectionMode="single" :headerClass="headerModeClass" :bodyClass="bodyModeClass"></Column> <Column selectionMode="single" :headerClass="headerModeClass" :bodyClass="bodyModeClass"></Column>
<Column field="key" header="Attribute" :headerClass="headerClass" :bodyClass="bodyClass" sortable></Column> <Column field="key" header="Attribute" :headerClass="headerClass" :bodyClass="bodyClass" sortable></Column>
</DataTable> </DataTable>
@@ -32,7 +32,7 @@
</div> </div>
<!-- type: string --> <!-- type: string -->
<div v-else-if="selectedAttName.type === 'string'" class="w-full"> <div v-else-if="selectedAttName.type === 'string'" class="w-full">
<DataTable v-model:selection="selectedAttRange" :value="attRangeData" dataKey="id" breakpoint="0" tableClass="w-full !border-separate !border-spacing-x-2 !table-auto text-sm" @row-select="onRowSelect"> <DataTable v-model:selection="selectedAttRange" :value="attRangeData" dataKey="id" breakpoint="0" tableClass="w-full !border-separate !border-spacing-x-2 !table-auto text-sm" @row-select="onRowSelect" @row-unselect="onRowUnselect" @row-select-all="onRowSelectAll($event)" @row-unselect-all="onRowUnelectAll">
<ColumnGroup type="header"> <ColumnGroup type="header">
<Row> <Row>
<Column selectionMode="multiple" :headerClass="headerModeClass" ></Column> <Column selectionMode="multiple" :headerClass="headerModeClass" ></Column>
@@ -241,11 +241,14 @@ export default {
} }
return sliderData; return sliderData;
}, },
// user select time start and end // user select value type start and end
attValueTypeStartEnd: function() { attValueTypeStartEnd: function() {
let start; let start;
let end; let end;
switch (this.selectedAttName.type) { let data;
const type = this.selectedAttName.type;
switch (type) {
case 'date': case 'date':
start = getMoment(this.startTime).format('YYYY-MM-DDTHH:mm:00'); start = getMoment(this.startTime).format('YYYY-MM-DDTHH:mm:00');
end = getMoment(this.endTime).format('YYYY-MM-DDTHH:mm:00'); end = getMoment(this.endTime).format('YYYY-MM-DDTHH:mm:00');
@@ -255,18 +258,77 @@ export default {
end = this.valueEnd; end = this.valueEnd;
break; break;
} }
// this.selectTimeFrame = [start, end]; // 傳給後端的資料 data = { // 傳給後端的資料
// this.$emit('on-row-select', e.data); type: type,
data: {
key: this.selectedAttName.key,
min: start,
max: end,
}
}
this.$emit('select-attribute', data);
return [start, end]; return [start, end];
}, },
}, },
methods: { methods: {
/** /**
* 切換 Attribute Name 或選取類別型 table 的選項 * 選取類別型 table 的選項
*/
onRowSelect() {
const type = this.selectedAttName.type;
const data = {
type: type,
data: this.selectedAttRange,
};
this.$emit('select-attribute', data);
},
/**
* 取消類別型 table 的選項
*/
onRowUnselect() {
const type = this.selectedAttName.type;
const data = {
type: type,
data: this.selectedAttRange,
};
this.$emit('select-attribute', data);
},
/**
* 選取類別型 table 的全選項
* @param {event} e * @param {event} e
*/ */
onRowSelect(e) { onRowSelectAll(e) {
this.selectedAttRange = e.data;
const type = this.selectedAttName.type;
const data = {
type: type,
data: this.selectedAttRange,
};
this.$emit('select-attribute', data);
},
/**
* 取消類別型 table 的全選項
*/
onRowUnelectAll() {
this.selectedAttRange = null;
const type = this.selectedAttName.type;
const data = {
type: type,
data: this.selectedAttRange,
};
this.$emit('select-attribute', data)
},
/**
* 切換 Attribute Name Radio
* @param {event} e
*/
switchAttNameRadio(e) {
this.selectedAttRange = null;
this.startTime = null;
this.endTime = null;
this.valueStart = null;
this.valueEnd = null;
if(this.valueData) { // 切換 Attribute Name if(this.valueData) { // 切換 Attribute Name
// 初始化雙向綁定 // 初始化雙向綁定
this.selectArea = [0, this.selectRange]; this.selectArea = [0, this.selectRange];
@@ -304,8 +366,6 @@ export default {
this.attValueTypeStartEnd; this.attValueTypeStartEnd;
// 建立圖表 // 建立圖表
this.createChart(); this.createChart();
} else { // 選取類別型 table 的選項
// this.$emit('on-row-select', e.data);
} }
}, },
/** /**
@@ -513,9 +573,29 @@ export default {
else return; else return;
}, },
}, },
created() {
this.$emitter.on('map-filter-reset', value => {
if(value) {
this.selectedAttRange = null;
if(this.valueData && this.valueTypes.includes(this.selectedAttName.type)){
const min = this.valueData.min;
const max = this.valueData.max;
this.startTime = new Date(min);
this.endTime = new Date(max);
this.valueStart = min;
this.valueEnd = max;
this.selectArea = [0, this.selectRange];
this.resizeMask(this.chartComplete);
}
}
});
},
mounted() { mounted() {
// Slider // Slider
this.selectArea = [0, this.selectRange]; // 初始化滑塊 this.selectArea = [0, this.selectRange]; // 初始化滑塊
},
beforeUnmount() {
this.selectedAttName = {};
} }
} }
</script> </script>

View File

@@ -85,7 +85,7 @@
</div> </div>
</div> </div>
<!-- title: Attributes --> <!-- title: Attributes -->
<Attributes v-if="selectValue[0] === 'Attributes'"></Attributes> <Attributes v-if="selectValue[0] === 'Attributes'" @select-attribute="getSelectAttribute"></Attributes>
<!-- title: Trace --> <!-- title: Trace -->
<Trace v-if="selectValue[0] === 'Trace'" ref="filterTraceView"></Trace> <Trace v-if="selectValue[0] === 'Trace'" ref="filterTraceView"></Trace>
<!-- title: Timeframes --> <!-- title: Timeframes -->
@@ -151,6 +151,8 @@ export default {
6: 'Contained in', 6: 'Contained in',
}, },
selectFilterTask: null, selectFilterTask: null,
selectAttType: '',
selectAttribute: null,
selectFilterStart: null, selectFilterStart: null,
selectFilterEnd: null, selectFilterEnd: null,
selectFilterStartToEnd: null, selectFilterStartToEnd: null,
@@ -199,6 +201,7 @@ export default {
isDisabledButton: function() { isDisabledButton: function() {
let disabled = true; let disabled = true;
let sele = this.selectValue; let sele = this.selectValue;
const type = this.selectAttType;
switch(sele[0]) { switch(sele[0]) {
case 'Sequence': // Filter Type 選 Sequence 的行為 case 'Sequence': // Filter Type 選 Sequence 的行為
@@ -224,6 +227,23 @@ export default {
break; break;
} }
break; break;
case 'Attributes': // Activity Sequence 選 Attributes 的行為
switch (type) {
case 'string':
if(this.selectAttribute && this.selectAttribute.length > 0) disabled = false;
break;
case 'boolean':
if(this.selectAttribute?.key && this.selectAttribute?.label) disabled = false;
break;
case 'int':
case 'float':
case 'date':
if(this.selectAttribute?.key && this.selectAttribute?.min && this.selectAttribute?.max) disabled = false;
break;
default:
break;
}
break;
case 'Trace': // Filter Type 選 Trace 的行為 case 'Trace': // Filter Type 選 Trace 的行為
disabled = false; disabled = false;
break; break;
@@ -315,6 +335,13 @@ export default {
list.sort((x, y) => y.occurrences_base - x.occurrences_base) list.sort((x, y) => y.occurrences_base - x.occurrences_base)
return list; return list;
}, },
/**
* @param {array} e select Attribute
*/
getSelectAttribute(e){
this.selectAttType = e.type;
this.selectAttribute = e.data;
},
/** /**
* @param {array} select select Have activity(s) rows * @param {array} select select Have activity(s) rows
*/ */
@@ -396,40 +423,54 @@ export default {
switch(e.type){ switch(e.type){
case "contains-task": case "contains-task":
label = `${includeStr}, ${e.task}` label = `${includeStr}, ${e.task}`;
type = "Sequence" type = "Sequence";
break break;
case "starts-with": case "starts-with":
label = `${includeStr}, start with ${e.task} ` label = `${includeStr}, start with ${e.task}`;
type = "Sequence" type = "Sequence";
break break;
case "ends-with": case "ends-with":
label = `${includeStr}, end with ${e.task} ` label = `${includeStr}, end with ${e.task}`;
type = "Sequence" type = "Sequence";
break break;
case "start-end": case "start-end":
label = `${includeStr}, start with ${e.starts_with}, end with ${e.ends_with}` label = `${includeStr}, start with ${e.starts_with}, end with ${e.ends_with}`;
type = "Sequence" type = "Sequence";
break break;
case "directly-follows": case "directly-follows":
label = `${includeStr}, directly follows, ${e.task_seq.join(' -> ')}` label = `${includeStr}, directly follows, ${e.task_seq.join(' -> ')}`;
type = "Sequence" type = "Sequence";
break break;
case "eventually-follows": case "eventually-follows":
label = `${includeStr}, eventually follows, ${e.task_seq.join(' -> ')}` label = `${includeStr}, eventually follows, ${e.task_seq.join(' -> ')}`;
type = "Sequence" type = "Sequence";
break break;
case "trace-freq":
label = `${includeStr}, from #${e.lower} to #${e.upper}`;
type = "Trace";
break;
case 'string-attr':
label = `${includeStr}, ${e.key}, ${e.value}`;
type = "Attributes";
break;
case 'boolean-attr':
label = `${includeStr}, ${e.key}, ${this.selectAttribute.label}`;
type = "Attributes";
break;
case 'int-attr':
case 'float-attr':
case 'date-attr':
label = `${includeStr}, ${e.key}, start with ${e.min}, end with ${e.max}`;
type = "Attributes";
break;
case "occurred-in": case "occurred-in":
case "started-in": case "started-in":
case "completed-in": case "completed-in":
case "occurred-around": case "occurred-around":
label = `${containmentMap[e.type]}, ${includeStr}, from ${getMoment(e.start).format("YYYY-MM-DD HH:mm:ss")} to ${getMoment(e.end).format("YYYY-MM-DD HH:mm:ss")} ` label = `${containmentMap[e.type]}, ${includeStr}, from ${getMoment(e.start).format("YYYY-MM-DD HH:mm:ss")} to ${getMoment(e.end).format("YYYY-MM-DD HH:mm:ss")} `
type = "Timeframe" type = "Timeframe"
break break;
case "trace-freq":
label = `${includeStr}, from #${e.lower} to #${e.upper}`
type = "Trace"
break
}; };
return { return {
type, type,
@@ -451,6 +492,10 @@ export default {
this.isStartSelected = null; this.isStartSelected = null;
this.isEndSelected = null; this.isEndSelected = null;
this.isActAllTask = true; this.isActAllTask = true;
// Attributes
this.selectAttType = '';
this.selectAttribute = null;
this.$emitter.emit('map-filter-reset', true);
// Timeframes // Timeframes
this.selectTimeFrame = []; this.selectTimeFrame = [];
// Trace // Trace
@@ -520,6 +565,55 @@ export default {
break; break;
} }
break; break;
case 'Attributes': // Activity Sequence 選 Attributes 的行為
switch (this.selectAttType) {
case 'string':
data = this.selectAttribute.map(task => {
return {
type: 'string-attr',
key: task.key,
value: task.value,
is_exclude: isExclude,
}
})
break;
case 'boolean':
data = {
type: 'boolean-attr',
key: this.selectAttribute.key,
value: this.selectAttribute.value,
is_exclude: isExclude,
}
break;
case 'int':
data = {
type: 'int-attr',
key: this.selectAttribute.key,
min: this.selectAttribute.min,
max: this.selectAttribute.max,
is_exclude: isExclude,
}
break
case 'float':
data = {
type: 'float-attr',
key: this.selectAttribute.key,
min: this.selectAttribute.min,
max: this.selectAttribute.max,
is_exclude: isExclude,
}
break
case 'date':
data = {
type: 'date-attr',
key: this.selectAttribute.key,
min: this.selectAttribute.min,
max: this.selectAttribute.max,
is_exclude: isExclude,
}
break
}
break;
case 'Trace': // Filter Type 選 Trace 的行為 case 'Trace': // Filter Type 選 Trace 的行為
let lowerIndex = this.$refs.filterTraceView.selectArea[0]; let lowerIndex = this.$refs.filterTraceView.selectArea[0];
let upperIndex = this.$refs.filterTraceView.selectArea[1]-1; let upperIndex = this.$refs.filterTraceView.selectArea[1]-1;

View File

@@ -97,22 +97,7 @@ export default defineStore('allMapDataStore', {
}, },
filterAttrs: state => { filterAttrs: state => {
if(state.allFilterAttrs !== null){ if(state.allFilterAttrs !== null){
state.allFilterAttrs.map(att => { state.allFilterAttrㄧㄠ
switch (att.type) {
case 'date':
att.min = att.min !== null ? moment(att.min).format('YYYY/MM/DD HH:mm') : null;
att.max = att.max !== null ? moment(att.max).format('YYYY/MM/DD HH:mm') : null;
break;
case 'float':
// Decimal.ROUND_UP|0: 無條件進位; Decimal.ROUND_DOWN|1: 無條件捨去。
att.min = att.min !== null ? Number(new Decimal(att.min).toFixed(2, 0)) : null;
att.max = att.max !== null ? Number(new Decimal(att.max).toFixed(2, 1)) : null;
break
default:
break;
}
return att;
});
return state.allFilterAttrs; return state.allFilterAttrs;
} }
}, },

View File

@@ -143,7 +143,8 @@
fileId = file.id; fileId = file.id;
type = 'log'; type = 'log';
params = { type: type, fileId: fileId }; params = { type: type, fileId: fileId };
this.$router.push({name: 'Map', params: params, query: params}); this.$router.push({name: 'Map', params: params});
// this.$router.push({name: 'Map', params: params, query: params});
break; break;
case 'Filter': case 'Filter':
this.createFilterId = file.id; this.createFilterId = file.id;
@@ -151,7 +152,8 @@
fileId = file.id; fileId = file.id;
type = 'filter'; type = 'filter';
params = { type: type, fileId: fileId }; params = { type: type, fileId: fileId };
this.$router.push({name: 'Map', params: params, query: params}); this.$router.push({name: 'Map', params: params});
// this.$router.push({name: 'Map', params: params, query: params});
break; break;
default: default:
break; break;