nested formula
This commit is contained in:
@@ -58,6 +58,13 @@ export default {
|
|||||||
computed: {
|
computed: {
|
||||||
isInlineSize () {
|
isInlineSize () {
|
||||||
return CSS.supports('container-type: size')
|
return CSS.supports('container-type: size')
|
||||||
|
},
|
||||||
|
fieldsUuidIndex () {
|
||||||
|
return this.fields.reduce((acc, field) => {
|
||||||
|
acc[field.uuid] = field
|
||||||
|
|
||||||
|
return acc
|
||||||
|
}, {})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async mounted () {
|
async mounted () {
|
||||||
@@ -96,8 +103,19 @@ export default {
|
|||||||
findPageElementForArea (area) {
|
findPageElementForArea (area) {
|
||||||
return (this.$root.$el?.parentNode?.getRootNode() || document).getElementById(`page-${area.attachment_uuid}-${area.page}`)
|
return (this.$root.$el?.parentNode?.getRootNode() || document).getElementById(`page-${area.attachment_uuid}-${area.page}`)
|
||||||
},
|
},
|
||||||
|
normalizeFormula (formula, depth = 0) {
|
||||||
|
if (depth > 10) return formula
|
||||||
|
|
||||||
|
return formula.replace(/{{(.*?)}}/g, (match, uuid) => {
|
||||||
|
if (this.fieldsUuidIndex[uuid]) {
|
||||||
|
return `(${this.normalizeFormula(this.fieldsUuidIndex[uuid].preferences.formula, depth + 1)})`
|
||||||
|
} else {
|
||||||
|
return match
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
calculateFormula (field) {
|
calculateFormula (field) {
|
||||||
const transformedFormula = field.preferences.formula.replace(/{{(.*?)}}/g, (match, uuid) => {
|
const transformedFormula = this.normalizeFormula(field.preferences.formula).replace(/{{(.*?)}}/g, (match, uuid) => {
|
||||||
return this.readonlyValues[uuid] || this.values[uuid] || 0.0
|
return this.readonlyValues[uuid] || this.values[uuid] || 0.0
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -28,14 +28,21 @@
|
|||||||
class="link"
|
class="link"
|
||||||
>{{ t('available_in_pro') }}</a>
|
>{{ t('available_in_pro') }}</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-inline mb-2 gap-2 space-y-1">
|
<div class="flex flex-wrap mb-2 gap-y-1 pt-1">
|
||||||
<button
|
<button
|
||||||
v-for="f in fields"
|
v-for="f in fields"
|
||||||
:key="f.uuid"
|
:key="f.uuid"
|
||||||
class="mr-1 btn btn-neutral btn-outline border-base-content/20 btn-sm normal-case font-normal bg-white !rounded-xl"
|
class="mr-1 flex btn btn-neutral btn-outline border-base-content/20 btn-sm normal-case font-normal bg-white !rounded-xl"
|
||||||
@click.prevent="insertTextUnderCursor(`{{${f.name || buildDefaultName(f, template.fields)}}}`)"
|
@click.prevent="insertTextUnderCursor(`{{${f.name || buildDefaultName(f, template.fields)}}}`)"
|
||||||
>
|
>
|
||||||
|
<IconMathFunction
|
||||||
|
v-if="f.preferences?.formula"
|
||||||
|
width="17"
|
||||||
|
height="17"
|
||||||
|
stroke-width="1.5"
|
||||||
|
/>
|
||||||
<IconCodePlus
|
<IconCodePlus
|
||||||
|
v-else
|
||||||
width="20"
|
width="20"
|
||||||
height="20"
|
height="20"
|
||||||
stroke-width="1.5"
|
stroke-width="1.5"
|
||||||
@@ -122,12 +129,13 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { IconCodePlus } from '@tabler/icons-vue'
|
import { IconCodePlus, IconMathFunction } from '@tabler/icons-vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'FormulaModal',
|
name: 'FormulaModal',
|
||||||
components: {
|
components: {
|
||||||
IconCodePlus
|
IconCodePlus,
|
||||||
|
IconMathFunction
|
||||||
},
|
},
|
||||||
inject: ['t', 'save', 'template', 'withFormula'],
|
inject: ['t', 'save', 'template', 'withFormula'],
|
||||||
props: {
|
props: {
|
||||||
@@ -154,7 +162,7 @@ export default {
|
|||||||
computed: {
|
computed: {
|
||||||
fields () {
|
fields () {
|
||||||
return this.template.fields.reduce((acc, f) => {
|
return this.template.fields.reduce((acc, f) => {
|
||||||
if (f !== this.field && ['number'].includes(f.type) && (!f.preferences?.formula || f.submitter_uuid !== this.field.submitter_uuid)) {
|
if (f !== this.field && ['number'].includes(f.type) && (!f.preferences?.formula || !f.preferences.formula.includes(this.field.uuid))) {
|
||||||
acc.push(f)
|
acc.push(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -189,6 +189,8 @@ module Submitters
|
|||||||
|
|
||||||
next if formula.blank?
|
next if formula.blank?
|
||||||
|
|
||||||
|
formula = normalize_formula(formula, submitter.submission)
|
||||||
|
|
||||||
submission_values ||=
|
submission_values ||=
|
||||||
if submitter.submission.template_submitters.size > 1
|
if submitter.submission.template_submitters.size > 1
|
||||||
merge_submitters_values(submitter)
|
merge_submitters_values(submitter)
|
||||||
@@ -202,6 +204,20 @@ module Submitters
|
|||||||
computed_values.compact_blank
|
computed_values.compact_blank
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def normalize_formula(formula, submission, depth = 0)
|
||||||
|
raise ValidationError, 'Formula infinite loop' if depth > 10
|
||||||
|
|
||||||
|
formula.gsub(/{{(.*?)}}/) do |match|
|
||||||
|
uuid = Regexp.last_match(1)
|
||||||
|
|
||||||
|
if (nested_formula = submission.fields_uuid_index.dig(uuid, 'preferences', 'formula').presence)
|
||||||
|
"(#{normalize_formula(nested_formula, submission, depth + 1)})"
|
||||||
|
else
|
||||||
|
match
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def calculate_formula_value(_formula, _values)
|
def calculate_formula_value(_formula, _values)
|
||||||
0
|
0
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user