Created
September 20, 2023 06:12
-
-
Save highoncarbs/2dff7ab7f412c5db1aa466c05bd454bc to your computer and use it in GitHub Desktop.
Code for Formula Builder
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<div class="container"> | |
<p class="is-size-5 has-text-weight-semibold">Formula Builder</p> | |
<br /> | |
<!-- Entry Form --> | |
<div class=""> | |
<div class=""> | |
<div class=""> | |
<div class="control"> | |
<b-field label="Salary Formula Builder" :type="{ 'is-danger': form.errors.name }"> | |
<b-input type="text" v-model="form.name" ref="name" placeholder="Enter Salary Formula Name" /> | |
</b-field> | |
</div> | |
<br /> | |
<div class="mb-3"> | |
<div class="level is-mobile"> | |
<div class="level-left"> | |
<b-field grouped class="level-item"> | |
<b-select placeholder="Select condition"> | |
<option :value="row.value" v-for="(row, index) in operators.conditions">{{ row.name }}</option> | |
</b-select> | |
<p class="control"> | |
<button @click.prevent="addRowPlus" class="button is-link"> | |
Add new group | |
</button> | |
</p> | |
</b-field> | |
<!-- <b-field grouped class="level-item"> | |
<b-select placeholder="Select a name"> | |
<option :value="row.value" v-for="(row, index) in operators.conditions">{{ row.name }}</option> | |
</b-select> | |
<p class="control"> | |
<button @click.prevent="addGroupPlus" class="button is-link"> | |
Add New Group | |
</button> | |
</p> | |
</b-field> --> | |
<!-- <button class="button is-link level-item"> | |
Add Condition | |
</button> | |
<button class="button is-light level-item"> | |
Add Formula | |
</button> --> | |
</div> | |
</div> | |
</div> | |
<table class="table is-fullwidth"> | |
<tr class="box pt-2 box-ss " | |
v-for="( row, index ) in structure_list " | |
:key="index"> | |
<div class=""> | |
<div class="level py-0 my-0 is-mobile"> | |
<div class="level-left"> | |
<div class="level-item has-text-weight-semibold"> | |
{{ index + 1 }}. | |
</div> | |
</div> | |
<div class="level-right"> | |
<button class="button level-item is-text"> | |
<b-icon icon="content-duplicate"> </b-icon> | |
</button> | |
<button @click.prevent="deleteRow(index)" class="button level-item is-text"> | |
<b-icon icon="close"> </b-icon> | |
</button> | |
</div> | |
</div> | |
<b-field grouped> | |
<b-field label-position="on-border" label="Select Master" :type="{ 'is-danger': errors.first_master }"> | |
<b-autocomplete open-on-focus select-on-click-outside keep-first ref="first_master" field="name" | |
v-model="row.query_first_master" @select="(option) => row.first_master = option" | |
icon-right="chevron-down" :data="data_master_filter" @typing="filteredMasterArray(index, 'first')" | |
icon="magnify" placeholder="Select Master"> | |
<template #header> | |
<span class="has-text-link is-clickable" @click="showAddData('location', index)"> | |
<span>Add new...</span> | |
</span> | |
</template> | |
</b-autocomplete> | |
</b-field> | |
<b-field label="Operator" label-position="on-border" :type="{ 'is-danger': errors.percentage }"> | |
<b-select expanded v-model="row.operator"> | |
<option :value="row.value" v-for="(row, index) in operators.math">{{ row.name }}</option> | |
</b-select> | |
</b-field> | |
<b-field label="Data Type" label-position="on-border" :type="{ 'is-danger': errors.percentage }"> | |
<b-select expanded v-model="row.option_for_second"> | |
<option value="value">Value</option> | |
<option value="master">Master</option> | |
</b-select> | |
</b-field> | |
<b-field v-if="row.option_for_second == 'value'" label-position="on-border" label="Value" | |
:type="{ 'is-danger': errors.percentage }"> | |
<b-input type="number" step="0.01" v-model="row.second_value"></b-input> | |
</b-field> | |
<b-field v-if="row.option_for_second == 'master'" label-position="on-border" | |
label="Select Second Master" :type="{ 'is-danger': errors.second_master }"> | |
<b-autocomplete open-on-focus select-on-click-outside keep-first ref="first_master" field="name" | |
v-model="row.query_second_master" @select="(option) => row.second_master = option" | |
icon-right="chevron-down" :data="data_master_filter" @typing="filteredMasterArray(index, 'second')" | |
icon="magnify" placeholder="Select Master"> | |
<template #header> | |
<span class="has-text-link is-clickable" @click="showAddData('location', index)"> | |
<span>Add new...</span> | |
</span> | |
</template> | |
</b-autocomplete> | |
</b-field> | |
</b-field> | |
<!-- <b-select v-model="row.append_operator" placeholder="Select condition"> | |
<option :value="row.value" v-for="(row, index) in operators.conditions">{{ row.name }}</option> | |
</b-select> --> | |
<!-- <p class="heading">Add rule to this group</p> --> | |
<b-field grouped> | |
<b-field label-position="on-border" label="Select Conditions"> | |
<b-select v-model="row.append_operator" aria-label=""> | |
<option :value="con.value" v-for="(con , index_con) in operators.conditions"> | |
{{ con.name }} | |
</option> | |
</b-select> | |
</b-field> | |
<p class="control"> | |
<button @click.prevent="addInnerRowPlus(index)" class="button is-link"> | |
Add Rule | |
</button> | |
</p> | |
</b-field> | |
<tr class="box pt-2 box-ss " | |
v-for="( row_inn, index_inner ) in row.inner " | |
:key="index_inner"> | |
<div class=""> | |
<div class="level py-0 my-0 is-mobile"> | |
<div class="level-left"> | |
<div class="level-item has-text-weight-semibold"> | |
<span class="has-text-grey"> | |
{{ index + 1 }} | |
</span> | |
. | |
<span class="has-text-grey"> | |
{{ index_inner + 1 }} | |
</span> | |
</div> | |
</div> | |
<div class="level-right"> | |
<button class="button level-item is-text"> | |
<b-icon icon="content-duplicate"> </b-icon> | |
</button> | |
<button @click.prevent="deleteInnerRow(index, index_inner)" class="button level-item is-text"> | |
<b-icon icon="close"> </b-icon> | |
</button> | |
</div> | |
</div> | |
<b-field grouped> | |
<b-field label-position="on-border" label="Select Master" :type="{ 'is-danger': errors.first_master }"> | |
<b-autocomplete open-on-focus select-on-click-outside keep-first ref="first_master" field="name" | |
v-model="row_inn.query_first_master" @select="(option) => row_inn.first_master = option" | |
icon-right="chevron-down" :data="data_master_filter" | |
@typing="filteredMasterInnerArray(index, index_inner, 'first')" icon="magnify" | |
placeholder="Select Master"> | |
<!-- <template #header> | |
<span class="has-text-link is-clickable" @click="showAddData('location', index)"> | |
<span>Add new...</span> | |
</span> | |
</template> --> | |
</b-autocomplete> | |
</b-field> | |
<b-field label="Operator" label-position="on-border" :type="{ 'is-danger': errors.percentage }"> | |
<b-select expanded v-model="row_inn.operator"> | |
<option :value="row_op.value" v-for="(row_op, index) in operators.math">{{ row_op.name }}</option> | |
</b-select> | |
</b-field> | |
<b-field label="Data Type" label-position="on-border" :type="{ 'is-danger': errors.percentage }"> | |
<b-select expanded v-model="row_inn.option_for_second"> | |
<option value="value">Value</option> | |
<option value="master">Master</option> | |
</b-select> | |
</b-field> | |
<b-field v-if="row_inn.option_for_second == 'value'" label-position="on-border" label="Value" | |
:type="{ 'is-danger': errors.percentage }"> | |
<b-input type="number" step="0.01" v-model="row_inn.second_value"></b-input> | |
</b-field> | |
<b-field v-if="row_inn.option_for_second == 'master'" label-position="on-border" | |
label="Select Second Master" :type="{ 'is-danger': errors.second_master }"> | |
<b-autocomplete open-on-focus select-on-click-outside keep-first ref="first_master" field="name" | |
v-model="row_inn.query_second_master" @select="(option) => row_inn.second_master = option" | |
icon-right="chevron-down" :data="data_master_filter" | |
@typing="filteredMasterInnerArray(index, index_inner, 'second')" icon="magnify" | |
placeholder="Select Master"> | |
<template #header> | |
<span class="has-text-link is-clickable" @click="showAddData('location', index)"> | |
<span>Add new...</span> | |
</span> | |
</template> | |
</b-autocomplete> | |
</b-field> | |
</b-field> | |
<b-field grouped> | |
<b-field label-position="on-border" label="Select Conditions"> | |
<b-select v-model="row_inn.append_operator" aria-label=""> | |
<option :value="con.value" v-for="(con , index_con) in operators.conditions"> | |
{{ con.name }} | |
</option> | |
</b-select> | |
</b-field> | |
<p class="control"> | |
<button @click.prevent="addSubInnerRowPlus(index, index_inner)" class="button is-link"> | |
Add Sub-Rule | |
</button> | |
</p> | |
</b-field> | |
<!-- 2nd Level --> | |
<tr class="box pt-2 box-ss " | |
v-for="( row_inn_inn, index_inner_inn ) in row_inn.inner " | |
:key="index_inner"> | |
<div class=""> | |
<div class="level py-0 my-0 is-mobile"> | |
<div class="level-left"> | |
<div class="level-item has-text-weight-semibold"> | |
<span class="has-text-grey"> | |
{{ index + 1 }} | |
</span> | |
. | |
<span class="has-text-grey"> | |
{{ index_inner + 1 }} | |
</span> | |
. | |
<span class="has-text-grey"> | |
{{ index_inner_inn + 1 }} | |
</span> | |
</div> | |
</div> | |
<div class="level-right"> | |
<button class="button level-item is-text"> | |
<b-icon icon="content-duplicate"> </b-icon> | |
</button> | |
<button @click.prevent="deleteSubInnerRow(index, index_inner, index_inner_inn)" | |
class="button level-item is-text"> | |
<b-icon icon="close"> </b-icon> | |
</button> | |
</div> | |
</div> | |
<b-field grouped> | |
<b-field label-position="on-border" label="Select Master" :type="{ 'is-danger': errors.first_master }"> | |
<b-autocomplete open-on-focus select-on-click-outside keep-first ref="first_master" field="name" | |
v-model="row_inn_inn.query_first_master" @select="(option) => row_inn_inn.first_master = option" | |
icon-right="chevron-down" :data="data_master_filter" | |
@typing="filteredMasterSubInnerArray(index, index_inner, index_inner_inn, 'first')" icon="magnify" | |
placeholder="Select Master"> | |
<!-- <template #header> | |
<span class="has-text-link is-clickable" @click="showAddData('location', index)"> | |
<span>Add new...</span> | |
</span> | |
</template> --> | |
</b-autocomplete> | |
</b-field> | |
<b-field label="Operator" label-position="on-border" :type="{ 'is-danger': errors.percentage }"> | |
<b-select expanded v-model="row_inn_inn.operator"> | |
<option :value="row_op.value" v-for="(row_op, index) in operators.math">{{ row_op.name }}</option> | |
</b-select> | |
</b-field> | |
<b-field label="Data Type" label-position="on-border" :type="{ 'is-danger': errors.percentage }"> | |
<b-select expanded v-model="row_inn_inn.option_for_second"> | |
<option value="value">Value</option> | |
<option value="master">Master</option> | |
</b-select> | |
</b-field> | |
<b-field v-if="row_inn_inn.option_for_second == 'value'" label-position="on-border" label="Value" | |
:type="{ 'is-danger': errors.percentage }"> | |
<b-input type="number" step="0.01" v-model="row_inn_inn.second_value"></b-input> | |
</b-field> | |
<b-field v-if="row_inn_inn.option_for_second == 'master'" label-position="on-border" | |
label="Select Second Master" :type="{ 'is-danger': errors.second_master }"> | |
<b-autocomplete open-on-focus select-on-click-outside keep-first ref="first_master" field="name" | |
v-model="row_inn_inn.query_second_master" @select="(option) => row_inn_inn.second_master = option" | |
icon-right="chevron-down" :data="data_master_filter" | |
@typing="filteredMasterSubInnerArray(index, index_inner, index_inner_inn, 'second')" icon="magnify" | |
placeholder="Select Master"> | |
<template #header> | |
<span class="has-text-link is-clickable" @click="showAddData('location', index)"> | |
<span>Add new...</span> | |
</span> | |
</template> | |
</b-autocomplete> | |
</b-field> | |
</b-field> | |
<!-- <b-field grouped> | |
<p class="control"> | |
<button @click.prevent="addSubInnerRowPlus(index, index_inner)" class="button is-link"> | |
Add Rule | |
</button> | |
</p> | |
</b-field> --> | |
</div> | |
</tr> | |
</div> | |
</tr> | |
</div> | |
</tr> | |
</table> | |
<div class="notification is-link is-light is-size-5"> | |
{{ getComputedFormula }} | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</template> | |
<script> | |
export default { | |
layout: "admin", | |
data() { | |
return { | |
view: true, | |
form: { | |
errors: {}, | |
id: null, | |
name: null, | |
}, | |
structure_list: [ | |
{ | |
position: null, | |
first_master: null, | |
query_first_master: "", | |
operator: null, | |
option_for_second: 'value', | |
second_value: "", | |
query_second_master: "", | |
second_master: null, | |
second_value: null, | |
append_operator: null, | |
errors: {}, | |
inner: [], | |
} | |
], | |
errors: {}, | |
isSubmitting: false, | |
data: [], | |
loading: false, | |
loading_set: false, | |
modal: false, | |
data_master_filter: [], | |
data_master: [], | |
query_search: "", | |
query_location_second: "", | |
add_to_formula: null, | |
operators: { | |
conditions: [ | |
{ | |
name: 'All should be true', | |
value: 'and' | |
}, | |
{ | |
name: 'Any should be true', | |
value: 'or' | |
} | |
], | |
math: [ | |
{ | |
name: 'Equals', | |
value: '=' | |
}, | |
{ | |
name: 'Add', | |
value: '+' | |
}, | |
{ | |
name: 'Subtract', | |
value: '-' | |
}, | |
{ | |
name: 'Multiply', | |
value: '*' | |
}, | |
{ | |
name: 'Divide', | |
value: '/' | |
}, | |
{ | |
name: 'Greater Than', | |
value: '>' | |
}, | |
{ | |
name: 'Less Than', | |
value: '<' | |
}, | |
{ | |
name: 'Greater Than Equal to', | |
value: '>=' | |
}, | |
{ | |
name: 'Less Than Equal to', | |
value: '<=' | |
}, | |
], | |
} | |
}; | |
}, | |
computed: { | |
getComputedFormula() { | |
let formula = ""; | |
this.structure_list.forEach(row => { | |
// Top level | |
if (row.first_master) { | |
formula = formula + ' ' + row.first_master.name | |
} | |
if (row.operator) { | |
formula = formula + ' ' + row.operator | |
} | |
if (row.option_for_second) { | |
if (row.option_for_second == 'value') { | |
if (row.second_value) { | |
formula = formula + ' ' + row.second_value | |
} | |
} | |
if (row.option_for_second == 'master') { | |
if (row.second_master) { | |
formula = formula + ' ' + row.second_master.name | |
} | |
} | |
} | |
if (row.append_operator) { | |
formula = formula + ' ::' + row.append_operator + '::' | |
} | |
row.inner.forEach(inner_row => { | |
if (inner_row.first_master) { | |
formula = formula + ' ' + inner_row.first_master.name | |
} | |
if (inner_row.operator) { | |
formula = formula + ' ' + inner_row.operator | |
} | |
if (inner_row.option_for_second) { | |
if (inner_row.option_for_second == 'value') { | |
if (inner_row.second_value) { | |
formula = formula + ' ' + inner_row.second_value | |
} | |
} | |
if (inner_row.option_for_second == 'master') { | |
if (inner_row.second_master) { | |
formula = formula + ' ' + inner_row.second_master.name | |
} | |
} | |
} | |
if (inner_row.append_operator) { | |
formula = formula + ' ::' + inner_row.append_operator + '::' | |
} | |
inner_row.inner.forEach(sub => { | |
if (sub.first_master) { | |
formula = formula + ' ' + sub.first_master.name | |
} | |
if (sub.operator) { | |
formula = formula + ' ' + sub.operator | |
} | |
if (sub.option_for_second) { | |
if (sub.option_for_second == 'value') { | |
if (sub.second_value) { | |
formula = formula + ' ' + sub.second_value | |
} | |
} | |
if (sub.option_for_second == 'master') { | |
if (sub.second_master) { | |
formula = formula + ' ' + sub.second_master.name | |
} | |
} | |
} | |
if (sub.append_operator) { | |
formula = formula + ' ::' + sub.append_operator + '::' | |
} | |
}) | |
}) | |
}); | |
return formula; | |
} | |
}, | |
mounted() { | |
this.$refs.name.focus(); | |
this.getData(); | |
}, | |
methods: { | |
deleteSubInnerRow(index, index_inner, index_inner_inn) { | |
console.log() | |
this.structure_list[index].inner[index_inner].inner.splice(index_inner_inn, 1) | |
}, | |
deleteInnerRow(index, index_inner) { | |
this.structure_list[index].inner.splice(index_inner, 1) | |
}, | |
deleteRow(index) { | |
this.structure_list.splice(index, 1) | |
}, | |
filteredMasterArray(index, master_pos) { | |
let data_point = this.structure_list[index]; | |
let query = ""; | |
if (master_pos == 'first') { | |
query = data_point.query_first_master; | |
} | |
if (master_pos == 'second') { | |
query = data_point.query_second_master; | |
} | |
if (query != "") { | |
this.data_master_filter = this.data_master.filter((option) => { | |
return ( | |
option.name | |
.toString() | |
.toLowerCase() | |
.indexOf(query.toLowerCase()) >= 0 | |
); | |
}); | |
} | |
return this.data_master_filter; | |
}, | |
filteredMasterInnerArray(index, index_inner, master_pos) { | |
let data_point = this.structure_list[index].inner[index_inner]; | |
let query = ""; | |
if (master_pos == 'first') { | |
query = data_point.query_first_master; | |
} | |
if (master_pos == 'second') { | |
query = data_point.query_second_master; | |
} | |
if (query != "") { | |
this.data_master_filter = this.data_master.filter((option) => { | |
return ( | |
option.name | |
.toString() | |
.toLowerCase() | |
.indexOf(query.toLowerCase()) >= 0 | |
); | |
}); | |
} | |
return this.data_master_filter; | |
}, | |
filteredMasterSubInnerArray(index, index_inner, index_inner_inn, master_pos) { | |
let data_point = this.structure_list[index].inner[index_inner].inner[index_inner_inn]; | |
let query = ""; | |
if (master_pos == 'first') { | |
query = data_point.query_first_master; | |
} | |
if (master_pos == 'second') { | |
query = data_point.query_second_master; | |
} | |
if (query != "") { | |
this.data_master_filter = this.data_master.filter((option) => { | |
return ( | |
option.name | |
.toString() | |
.toLowerCase() | |
.indexOf(query.toLowerCase()) >= 0 | |
); | |
}); | |
} | |
return this.data_master_filter; | |
}, | |
addRowPlus() { | |
let obj = | |
{ | |
position: null, | |
first_master: null, | |
query_first_master: "", | |
operator: null, | |
option_for_second: 'value', | |
query_second_master: "", | |
second_master: null, | |
second_value: null, | |
append_operator: null, | |
inner: [], | |
errors: {}, | |
} | |
this.structure_list.push(obj) | |
this.add_to_formula = null | |
}, | |
addInnerRowPlus(index) { | |
let obj = | |
{ | |
position: null, | |
first_master: null, | |
query_first_master: "", | |
operator: null, | |
option_for_second: 'value', | |
query_second_master: "", | |
second_master: null, | |
second_value: null, | |
append_operator: null, | |
inner: [], | |
errors: {}, | |
} | |
this.structure_list[index].inner.push(obj) | |
this.add_to_formula = null | |
}, | |
addSubInnerRowPlus(index, index_inner) { | |
let obj = | |
{ | |
position: null, | |
first_master: null, | |
query_first_master: "", | |
operator: null, | |
option_for_second: 'value', | |
query_second_master: "", | |
second_master: null, | |
second_value: null, | |
append_operator: null, | |
inner: [], | |
errors: {}, | |
} | |
this.structure_list[index].inner[index_inner].inner.push(obj) | |
}, | |
addRow(index) { | |
let obj = { | |
position: null, | |
first_master: null, | |
percentage: null, | |
second_master: null, | |
} | |
this.structure_list.push(obj) | |
}, | |
setData(dat_type, option) { | |
if (option) { | |
this.form[dat_type] = option; | |
} else { | |
this.form[dat_type] = null; | |
} | |
}, | |
checkData(e) { | |
this.form.errors = {}; | |
if (this.form.name) { | |
return true; | |
} | |
if (!this.form.name) { | |
this.$set(this.form.errors, "name", true); | |
} | |
}, | |
getData(e) { | |
let self = this; | |
this.loading = true; | |
this.$axios | |
.get("/masters/get/location") | |
.then(function (response) { | |
self.data_master = response.data; | |
}) | |
.catch(function (error) { | |
this.loading = false; | |
self.$buefy.snackbar.open({ | |
duration: 4000, | |
message: "Unable to fetch data", | |
type: "is-light", | |
position: "is-top-right", | |
actionText: "Close", | |
queue: true, | |
onAction: () => { | |
self.isActive = false; | |
}, | |
}); | |
}) | |
.finally(() => { | |
this.loading = false; | |
this.loading_set = true; | |
}); | |
}, | |
}, | |
}; | |
</script> | |
<style> | |
.box-ss { | |
border: 1px solid #dbdbdb; | |
box-shadow: none; | |
border-top: 3px solid lightblue; | |
} | |
</style> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment