mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-10-08 21:06:24 +08:00
Add stock filters [SCI-6547] (#3938)
Co-authored-by: Anton <anton@scinote.net>
This commit is contained in:
parent
97c15eaac0
commit
004aeda601
8 changed files with 183 additions and 2 deletions
|
@ -173,11 +173,16 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.stock-filter-attributes {
|
||||||
|
grid-template-columns: min-content auto 100px;
|
||||||
|
}
|
||||||
|
|
||||||
.number-range-selector {
|
.number-range-selector {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: .5em;
|
gap: .5em;
|
||||||
grid-auto-flow: column;
|
grid-auto-flow: column;
|
||||||
|
height: 2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown-selector-container {
|
.dropdown-selector-container {
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
import RepositoryStatusValue from 'vue/repository_filter/filters/repositoryStatusValue.vue'
|
import RepositoryStatusValue from 'vue/repository_filter/filters/repositoryStatusValue.vue'
|
||||||
import RepositoryChecklistValue from 'vue/repository_filter/filters/repositoryChecklistValue.vue'
|
import RepositoryChecklistValue from 'vue/repository_filter/filters/repositoryChecklistValue.vue'
|
||||||
import RepositoryUserValue from 'vue/repository_filter/filters/repositoryUserValue.vue'
|
import RepositoryUserValue from 'vue/repository_filter/filters/repositoryUserValue.vue'
|
||||||
|
import RepositoryStockValue from 'vue/repository_filter/filters/repositoryStockValue.vue'
|
||||||
import DropdownSelector from 'vue/shared/dropdown_selector.vue'
|
import DropdownSelector from 'vue/shared/dropdown_selector.vue'
|
||||||
|
|
||||||
|
|
||||||
|
@ -61,7 +62,8 @@
|
||||||
RepositoryStatusValue,
|
RepositoryStatusValue,
|
||||||
RepositoryChecklistValue,
|
RepositoryChecklistValue,
|
||||||
RepositoryListValue,
|
RepositoryListValue,
|
||||||
RepositoryUserValue
|
RepositoryUserValue,
|
||||||
|
RepositoryStockValue
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
updateFilter(value) {
|
updateFilter(value) {
|
||||||
|
|
|
@ -0,0 +1,127 @@
|
||||||
|
<template>
|
||||||
|
<div class="filter-attributes stock-filter-attributes">
|
||||||
|
<div class="operator-selector">
|
||||||
|
<DropdownSelector
|
||||||
|
:disableSearch="true"
|
||||||
|
:options="this.operators"
|
||||||
|
:selectedValue="this.operator"
|
||||||
|
:selectorId="`OperatorSelector${this.filter.id}`"
|
||||||
|
@dropdown:changed="updateOperator"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div v-if="operator !== 'between'" class="sci-input-container">
|
||||||
|
<input
|
||||||
|
class="sci-input-field"
|
||||||
|
type="text"
|
||||||
|
name="value"
|
||||||
|
v-model="value"
|
||||||
|
:placeholder= "this.i18n.t('repositories.show.repository_filter.filters.types.RepositoryStockValue.input_placeholder')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div v-else class="number-range-selector">
|
||||||
|
<div class="sci-input-container">
|
||||||
|
<input
|
||||||
|
class="sci-input-field"
|
||||||
|
type="text"
|
||||||
|
name="from"
|
||||||
|
v-model="from"
|
||||||
|
:placeholder= "this.i18n.t('repositories.show.repository_filter.filters.types.RepositoryStockValue.from_placeholder')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<span class="between-delimiter">—</span>
|
||||||
|
<div class="sci-input-container">
|
||||||
|
<input
|
||||||
|
class="sci-input-field"
|
||||||
|
type="text"
|
||||||
|
name="to"
|
||||||
|
v-model="to"
|
||||||
|
:placeholder= "this.i18n.t('repositories.show.repository_filter.filters.types.RepositoryStockValue.to_placeholder')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="stock-unit-filter-dropdown">
|
||||||
|
<DropdownSelector
|
||||||
|
:singleSelect="true"
|
||||||
|
:closeOnSelect="true"
|
||||||
|
:selectedValue="this.stock_unit"
|
||||||
|
:options="this.prepareUnitOptions()"
|
||||||
|
:selectorId="`StockUnitSelector${this.filter.id}`"
|
||||||
|
@dropdown:changed="updateStockUnit"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import FilterMixin from 'vue/repository_filter/mixins/filter.js'
|
||||||
|
import DropdownSelector from 'vue/shared/dropdown_selector.vue'
|
||||||
|
export default {
|
||||||
|
name: 'RepositoryStockValue',
|
||||||
|
mixins: [FilterMixin],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
operators: [
|
||||||
|
{ value: 'equal_to', label: this.i18n.t('repositories.show.repository_filter.filters.operators.equal_to')},
|
||||||
|
{ value: 'unequal_to', label: this.i18n.t('repositories.show.repository_filter.filters.operators.unequal_to') },
|
||||||
|
{ value: 'greater_than', label: this.i18n.t('repositories.show.repository_filter.filters.operators.greater_than') },
|
||||||
|
{ value: 'greater_than_or_equal_to', label: this.i18n.t('repositories.show.repository_filter.filters.operators.greater_than_or_equal_to') },
|
||||||
|
{ value: 'less_than', label: this.i18n.t('repositories.show.repository_filter.filters.operators.less_than') },
|
||||||
|
{ value: 'less_than_or_equal_to', label: this.i18n.t('repositories.show.repository_filter.filters.operators.less_than_or_equal_to') },
|
||||||
|
{ value: 'between', label: this.i18n.t('repositories.show.repository_filter.filters.operators.between') }
|
||||||
|
],
|
||||||
|
operator: 'equal_to',
|
||||||
|
value: '',
|
||||||
|
from: '',
|
||||||
|
to: '',
|
||||||
|
stock_unit: 'all'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
DropdownSelector
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
validateNumber(number) {
|
||||||
|
return number.replace(/[^0-9.]/g, '').match(/^\d*(\.\d{0,10})?/)[0]
|
||||||
|
},
|
||||||
|
|
||||||
|
prepareUnitOptions() {
|
||||||
|
return [
|
||||||
|
{ label: this.i18n.t('repositories.show.repository_filter.filters.types.RepositoryStockValue.all_units'), value: 'all'},
|
||||||
|
{ label: this.i18n.t('repositories.show.repository_filter.filters.types.RepositoryStockValue.no_unit'), value: 'none'}
|
||||||
|
].concat(this.filter.column.items);
|
||||||
|
},
|
||||||
|
|
||||||
|
updateStockUnit(value) {
|
||||||
|
this.stock_unit = value
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
stock_unit() {
|
||||||
|
this.parameters.stock_unit = this.stock_unit
|
||||||
|
this.updateFilter();
|
||||||
|
},
|
||||||
|
value() {
|
||||||
|
this.value = this.validateNumber(this.value)
|
||||||
|
this.parameters = { value: this.value, stock_unit: this.stock_unit }
|
||||||
|
this.updateFilter();
|
||||||
|
},
|
||||||
|
to() {
|
||||||
|
this.to = this.validateNumber(this.to)
|
||||||
|
this.parameters = {from: this.from, to: this.to, stock_unit: this.stock_unit}
|
||||||
|
this.updateFilter();
|
||||||
|
},
|
||||||
|
from() {
|
||||||
|
this.from = this.validateNumber(this.from)
|
||||||
|
this.parameters = {from: this.from, to: this.to, stock_unit: this.stock_unit}
|
||||||
|
this.updateFilter();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
isBlank(){
|
||||||
|
return (!this.value && this.operator != 'between') ||
|
||||||
|
((!this.to || !this.from) && this.operator == 'between');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -123,6 +123,7 @@ class RepositoryColumn < ApplicationRecord
|
||||||
|
|
||||||
def items
|
def items
|
||||||
items_method_name = "#{data_type.chomp('Value').underscore}_items"
|
items_method_name = "#{data_type.chomp('Value').underscore}_items"
|
||||||
|
items_method_name = 'repository_stock_unit_items' if data_type == 'RepositoryStockValue'
|
||||||
__send__(items_method_name) if respond_to?(items_method_name, true)
|
__send__(items_method_name) if respond_to?(items_method_name, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,6 @@ class RepositoryStockUnitItem < ApplicationRecord
|
||||||
validates :data, presence: true,
|
validates :data, presence: true,
|
||||||
uniqueness: { scope: :repository_column_id },
|
uniqueness: { scope: :repository_column_id },
|
||||||
length: { maximum: Constants::NAME_MAX_LENGTH }
|
length: { maximum: Constants::NAME_MAX_LENGTH }
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def validate_per_column_limit
|
def validate_per_column_limit
|
||||||
|
|
|
@ -24,6 +24,44 @@ class RepositoryStockValue < ApplicationRecord
|
||||||
amount <= low_stock_threshold
|
amount <= low_stock_threshold
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.add_filter_condition(repository_rows, join_alias, filter_element)
|
||||||
|
parameters = filter_element.parameters
|
||||||
|
if filter_element.operator == 'between'
|
||||||
|
return repository_rows if parameters['from'].blank? || parameters['to'].blank?
|
||||||
|
elsif parameters['value'].blank?
|
||||||
|
return repository_rows
|
||||||
|
end
|
||||||
|
|
||||||
|
repository_rows = case parameters['stock_unit']
|
||||||
|
when 'all'
|
||||||
|
repository_rows.where("#{join_alias}.repository_stock_unit_item_id IS NOT NULL")
|
||||||
|
when 'none'
|
||||||
|
repository_rows.where("#{join_alias}.repository_stock_unit_item_id IS NULL")
|
||||||
|
else
|
||||||
|
repository_rows.where("#{join_alias}.repository_stock_unit_item_id = ?", parameters['stock_unit'])
|
||||||
|
end
|
||||||
|
|
||||||
|
case filter_element.operator
|
||||||
|
when 'equal_to'
|
||||||
|
repository_rows.where("#{join_alias}.amount = ?", parameters['value'].to_d)
|
||||||
|
when 'unequal_to'
|
||||||
|
repository_rows.where.not("#{join_alias}.amount = ?", parameters['value'].to_d)
|
||||||
|
when 'greater_than'
|
||||||
|
repository_rows.where("#{join_alias}.amount > ?", parameters['value'].to_d)
|
||||||
|
when 'greater_than_or_equal_to'
|
||||||
|
repository_rows.where("#{join_alias}.amount >= ?", parameters['value'].to_d)
|
||||||
|
when 'less_than'
|
||||||
|
repository_rows.where("#{join_alias}.amount < ?", parameters['value'].to_d)
|
||||||
|
when 'less_than_or_equal_to'
|
||||||
|
repository_rows.where("#{join_alias}.amount <= ?", parameters['value'].to_d)
|
||||||
|
when 'between'
|
||||||
|
repository_rows
|
||||||
|
.where("#{join_alias}.amount > ? AND #{join_alias}.amount < ?", parameters['from'].to_d, parameters['to'].to_d)
|
||||||
|
else
|
||||||
|
raise ArgumentError, 'Wrong operator for RepositoryStockValue!'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def data_changed?(new_data)
|
def data_changed?(new_data)
|
||||||
BigDecimal(new_data.to_s) != data
|
BigDecimal(new_data.to_s) != data
|
||||||
end
|
end
|
||||||
|
|
|
@ -117,6 +117,8 @@ class Extends
|
||||||
table_name: :repository_date_time_values
|
table_name: :repository_date_time_values
|
||||||
}, RepositoryTimeRangeValue: {
|
}, RepositoryTimeRangeValue: {
|
||||||
table_name: :repository_date_time_range_values
|
table_name: :repository_date_time_range_values
|
||||||
|
}, RepositoryStockValue: {
|
||||||
|
table_name: :repository_stock_values
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,6 +141,7 @@ class Extends
|
||||||
RepositoryDateRangeValue
|
RepositoryDateRangeValue
|
||||||
RepositoryTimeValue
|
RepositoryTimeValue
|
||||||
RepositoryTimeRangeValue
|
RepositoryTimeRangeValue
|
||||||
|
RepositoryStockValue
|
||||||
)
|
)
|
||||||
|
|
||||||
# Array of preload relations used in search query for repository rows
|
# Array of preload relations used in search query for repository rows
|
||||||
|
|
|
@ -1504,6 +1504,12 @@ en:
|
||||||
select_placeholder: "Select user"
|
select_placeholder: "Select user"
|
||||||
multiple_selected: "users selected"
|
multiple_selected: "users selected"
|
||||||
all_selected: "All users selected"
|
all_selected: "All users selected"
|
||||||
|
RepositoryStockValue:
|
||||||
|
input_placeholder: "Enter numeric value"
|
||||||
|
to_placeholder: "To"
|
||||||
|
from_placeholder: "From"
|
||||||
|
all_units: "All units"
|
||||||
|
no_unit: "No unit"
|
||||||
bmt_search:
|
bmt_search:
|
||||||
bmt_filter: "Biomolecule filter"
|
bmt_filter: "Biomolecule filter"
|
||||||
save_filters: "Save filters"
|
save_filters: "Save filters"
|
||||||
|
|
Loading…
Add table
Reference in a new issue