Merge pull request '#2 -- Add inference dtos' (#22) from 2-execute-rules into master
All checks were successful
CI fuzzy controller / container-test-job (push) Successful in 1m2s

Reviewed-on: #22
This commit is contained in:
romanov73 2025-03-03 22:28:51 +04:00
commit 40fc94c20d
21 changed files with 408 additions and 157 deletions

View File

@ -46,8 +46,7 @@ dependencies {
implementation group: 'org.webjars', name: 'jquery', version: '3.6.0'
implementation group: 'org.webjars', name: 'bootstrap', version: '4.6.0'
implementation group: 'org.webjars', name: 'bootstrap-select', version: '1.13.8'
implementation group: 'org.webjars', name: 'font-awesome', version: '4.7.0'
implementation group: 'org.webjars', name: 'highcharts', version: '7.0.0'
implementation 'org.webjars.npm:bootstrap-icons:1.11.3'
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-test'
}

View File

@ -24,4 +24,18 @@ public class ProjectVariableService {
}
return variableRepository.findByProject(projectService.getById(projectId));
}
public List<Variable> getInputByProjectId(Integer projectId) {
if (projectId == null || projectId == 0) {
return Collections.emptyList();
}
return variableRepository.getInputByProject(projectService.getById(projectId));
}
public List<Variable> getOutputByProjectId(Integer projectId) {
if (projectId == null || projectId == 0) {
return Collections.emptyList();
}
return variableRepository.getOutputByProject(projectService.getById(projectId));
}
}

View File

@ -12,7 +12,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import ru.ulstu.fc.rule.model.FuzzyRuleForm;
import ru.ulstu.fc.rule.model.FuzzyTerm;
import ru.ulstu.fc.rule.model.Variable;
import ru.ulstu.fc.rule.model.dto.VariableDto;
import ru.ulstu.fc.rule.service.FuzzyRuleService;
import ru.ulstu.fc.rule.service.FuzzyTermService;
import ru.ulstu.fc.rule.service.VariableService;
@ -65,11 +65,26 @@ public class FuzzyRuleController {
@ResponseBody
@GetMapping("/getVariables/{projectId}")
public List<Variable> getVariables(@PathVariable("projectId") Integer projectId,
final HttpServletResponse response) {
public List<VariableDto> getVariables(@PathVariable("projectId") Integer projectId,
final HttpServletResponse response) {
response.addHeader("Cache-Control", "max-age=60, must-revalidate, no-transform");
//TODO: return DTO without terms
return variableService.getAllByProject(projectId);
return variableService.getAllDtoByProject(projectId);
}
@ResponseBody
@GetMapping("/getInputVariables/{projectId}")
public List<VariableDto> getInputVariables(@PathVariable("projectId") Integer projectId,
final HttpServletResponse response) {
response.addHeader("Cache-Control", "max-age=60, must-revalidate, no-transform");
return variableService.getInputVariablesDtoByProject(projectId);
}
@ResponseBody
@GetMapping("/getOutputVariables/{projectId}")
public List<VariableDto> getOutputVariables(@PathVariable("projectId") Integer projectId,
final HttpServletResponse response) {
response.addHeader("Cache-Control", "max-age=60, must-revalidate, no-transform");
return variableService.getOutputVariablesDtoByProject(projectId);
}
@ResponseBody

View File

@ -7,22 +7,34 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import ru.ulstu.fc.project.service.ProjectRulesService;
import ru.ulstu.fc.rule.model.FuzzyRule;
import ru.ulstu.fc.rule.model.FuzzyRuleForm;
import ru.ulstu.fc.rule.service.FuzzyRuleService;
import java.util.List;
@RestController
@RequestMapping("fuzzyRuleRest")
public class FuzzyRuleRestController {
private final FuzzyRuleService ruleService;
private final ProjectRulesService projectRulesService;
public FuzzyRuleRestController(FuzzyRuleService ruleService) {
public FuzzyRuleRestController(FuzzyRuleService ruleService,
ProjectRulesService projectRulesService) {
this.ruleService = ruleService;
this.projectRulesService = projectRulesService;
}
@GetMapping("/get/{projectId}/{ruleId}")
public FuzzyRule get(@PathVariable(value = "projectId") Integer projectId,
@PathVariable(value = "ruleId") Integer id) {
@GetMapping("/getAll/{projectId}")
public List<FuzzyRule> getAll(@PathVariable(value = "projectId") Integer projectId) {
//TODO: return dto
return projectRulesService.getByProjectId(projectId);
}
@GetMapping("/get/{ruleId}")
public FuzzyRule get(@PathVariable(value = "ruleId") Integer id) {
//TODO: return dto
return ruleService.getById(id);
}

View File

@ -6,6 +6,7 @@ import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import ru.ulstu.fc.rule.model.InferenceData;
import ru.ulstu.fc.rule.model.OutputValue;
import ru.ulstu.fc.rule.model.ProjectInferenceData;
import ru.ulstu.fc.rule.service.FuzzyInferenceService;
import java.util.List;
@ -24,6 +25,11 @@ public class InferenceRestController {
return fuzzyInferenceService.getFuzzyInference(inferenceData.getRules(),
inferenceData.getValues(),
inferenceData.getInputVariables(),
inferenceData.getOutputVariable());
inferenceData.getOutputVariables());
}
@RequestMapping(value = "getProjectInference", method = RequestMethod.POST)
public List<OutputValue> getProjectInference(@RequestBody ProjectInferenceData projectInferenceData) {
return fuzzyInferenceService.getProjectFuzzyInference(projectInferenceData);
}
}

View File

@ -7,7 +7,7 @@ public class InferenceData {
private List<String> rules;
private Map<String, Double> values;
private List<Variable> inputVariables;
private Variable outputVariable;
private List<Variable> outputVariables;
public List<String> getRules() {
return rules;
@ -33,11 +33,11 @@ public class InferenceData {
this.inputVariables = inputVariables;
}
public Variable getOutputVariable() {
return outputVariable;
public List<Variable> getOutputVariables() {
return outputVariables;
}
public void setOutputVariable(Variable outputVariable) {
this.outputVariable = outputVariable;
public void setOutputVariable(List<Variable> outputVariables) {
this.outputVariables = outputVariables;
}
}

View File

@ -1,10 +1,12 @@
package ru.ulstu.fc.rule.model;
public class OutputValue {
private String variable;
private String fuzzyTerm;
private Double degree;
public OutputValue(String fuzzyTerm, Double degree) {
public OutputValue(String variable, String fuzzyTerm, Double degree) {
this.variable = variable;
this.fuzzyTerm = fuzzyTerm;
this.degree = degree;
}
@ -24,4 +26,12 @@ public class OutputValue {
public void setDegree(Double degree) {
this.degree = degree;
}
public String getVariable() {
return variable;
}
public void setVariable(String variable) {
this.variable = variable;
}
}

View File

@ -0,0 +1,26 @@
package ru.ulstu.fc.rule.model;
import ru.ulstu.fc.rule.model.dto.VariableValueDto;
import java.util.List;
public class ProjectInferenceData {
private Integer projectId;
private List<VariableValueDto> variableValues;
public Integer getProjectId() {
return projectId;
}
public void setProjectId(Integer projectId) {
this.projectId = projectId;
}
public List<VariableValueDto> getVariableValues() {
return variableValues;
}
public void setVariableValues(List<VariableValueDto> variableValues) {
this.variableValues = variableValues;
}
}

View File

@ -0,0 +1,42 @@
package ru.ulstu.fc.rule.model.dto;
import ru.ulstu.fc.rule.model.FuzzyTerm;
public class FuzzyTermDto {
private Integer id;
private String description;
private Double crispValue;
public FuzzyTermDto() {
}
public FuzzyTermDto(FuzzyTerm fuzzyTerm) {
this.description = fuzzyTerm.getDescription();
this.crispValue = fuzzyTerm.getCrispValue();
this.id = fuzzyTerm.getId();
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Double getCrispValue() {
return crispValue;
}
public void setCrispValue(Double crispValue) {
this.crispValue = crispValue;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
}

View File

@ -0,0 +1,55 @@
package ru.ulstu.fc.rule.model.dto;
import ru.ulstu.fc.rule.model.Variable;
import java.util.ArrayList;
import java.util.List;
public class VariableDto {
private Integer id;
private String name;
private boolean input;
private List<FuzzyTermDto> terms = new ArrayList<>();
public VariableDto() {
}
public VariableDto(Variable variable) {
this.id = variable.getId();
this.name = variable.getName();
this.terms = variable.getFuzzyTerms().stream().map(FuzzyTermDto::new).toList();
this.input = variable.isInput();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<FuzzyTermDto> getTerms() {
return terms;
}
public void setTerms(List<FuzzyTermDto> terms) {
this.terms = terms;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public boolean isInput() {
return input;
}
public void setInput(boolean input) {
this.input = input;
}
}

View File

@ -0,0 +1,22 @@
package ru.ulstu.fc.rule.model.dto;
public class VariableValueDto {
private String variableName;
private Double value;
public String getVariableName() {
return variableName;
}
public void setVariableName(String variableName) {
this.variableName = variableName;
}
public Double getValue() {
return value;
}
public void setValue(Double value) {
this.value = value;
}
}

View File

@ -1,6 +1,8 @@
package ru.ulstu.fc.rule.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import ru.ulstu.fc.project.model.Project;
import ru.ulstu.fc.rule.model.Variable;
@ -11,4 +13,10 @@ public interface VariableRepository extends JpaRepository<Variable, Integer> {
List<Variable> findByProject(Project project);
List<Variable> getByProject(Project project);
@Query("SELECT v FROM Variable v WHERE v.project = :project AND v.input = true")
List<Variable> getInputByProject(@Param("project") Project project);
@Query("SELECT v FROM Variable v WHERE v.project = :project AND v.input = false")
List<Variable> getOutputByProject(@Param("project") Project project);
}

View File

@ -14,10 +14,17 @@ import com.fuzzylite.variable.OutputVariable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import ru.ulstu.fc.project.service.ProjectRulesService;
import ru.ulstu.fc.project.service.ProjectService;
import ru.ulstu.fc.project.service.ProjectVariableService;
import ru.ulstu.fc.rule.model.FuzzyRule;
import ru.ulstu.fc.rule.model.FuzzyTerm;
import ru.ulstu.fc.rule.model.OutputValue;
import ru.ulstu.fc.rule.model.ProjectInferenceData;
import ru.ulstu.fc.rule.model.Variable;
import ru.ulstu.fc.rule.model.dto.VariableValueDto;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@ -31,9 +38,17 @@ public class FuzzyInferenceService {
+ " is %s";
private final static String NO_RESULT = "Нет результата";
private final Engine fuzzyEngine;
private final ProjectService projectService;
private final FuzzyRuleService fuzzyRuleService;
private final ProjectRulesService projectRulesService;
private final ProjectVariableService projectVariableService;
public FuzzyInferenceService(Engine fuzzyEngine) {
public FuzzyInferenceService(Engine fuzzyEngine, ProjectService projectService, FuzzyRuleService fuzzyRuleService, ProjectRulesService projectRulesService, ProjectVariableService projectVariableService) {
this.fuzzyEngine = fuzzyEngine;
this.projectService = projectService;
this.fuzzyRuleService = fuzzyRuleService;
this.projectRulesService = projectRulesService;
this.projectVariableService = projectVariableService;
}
private List<String> getDemoRules() {
@ -48,6 +63,7 @@ public class FuzzyInferenceService {
final InputVariable input = new InputVariable();
input.setName(variable.getName());
input.setDescription("");
variable.getFuzzyTerms().sort(Comparator.comparing(FuzzyTerm::getCrispValue));
input.setRange(0, variable.getFuzzyTerms().get(variable.getFuzzyTerms().size() - 1).getCrispValue());
input.setEnabled(true);
input.setLockValueInRange(false);
@ -89,9 +105,9 @@ public class FuzzyInferenceService {
private RuleBlock getRuleBlock(Engine engine,
List<String> rules,
List<Variable> inputVariables,
Variable outputVariable) {
List<Variable> outputVariables) {
inputVariables.stream().map(this::getInputVariable).forEach(engine::addInputVariable);
engine.addOutputVariable(getOutputVariable(outputVariable));
outputVariables.stream().map(this::getOutputVariable).forEach(engine::addOutputVariable);
RuleBlock mamdani = new RuleBlock();
mamdani.setName("mamdani");
@ -106,22 +122,21 @@ public class FuzzyInferenceService {
}
private List<OutputValue> getConsequent(Engine engine, Map<String, Double> variableValues) {
OutputVariable outputVariable = engine.getOutputVariable(OUTPUT_VARIABLE_NAME);
List<OutputVariable> outputVariables = engine.getOutputVariables();
for (Map.Entry<String, Double> variableValue : variableValues.entrySet()) {
InputVariable inputVariable = engine.getInputVariable(variableValue.getKey());
inputVariable.setValue(variableValue.getValue());
}
engine.process();
if (outputVariable != null) {
LOG.info("Output: {}", outputVariable.getValue());
}
return Double.isNaN(outputVariable.getValue())
? List.of(new OutputValue(NO_RESULT, 0.0))
: outputVariable.fuzzyOutput()
.getTerms()
return outputVariables
.stream()
.map(t -> new OutputValue(t.getTerm().getName(), t.getDegree()))
.collect(Collectors.toList());
.filter(v -> !Double.isNaN(v.getValue()))
.map(OutputVariable::fuzzyOutput)
.map(a -> new OutputValue(a.getName(),
a.getTerms().getFirst().getTerm().getName(),
a.getTerms().getFirst().getDegree()))
.toList();
}
public List<OutputValue> getFuzzyInference(Map<String, Double> vals) {
@ -137,19 +152,40 @@ public class FuzzyInferenceService {
new FuzzyTerm("высокий", 500000.0))
)
),
new Variable("кредит", List.of(
List.of(new Variable("кредит", List.of(
new FuzzyTerm("небольшой", 20000.0),
new FuzzyTerm("средний", 100000.0),
new FuzzyTerm("большой", 1000000.0)))
new FuzzyTerm("большой", 1000000.0))))
);
}
public List<OutputValue> getFuzzyInference(List<String> rules,
Map<String, Double> values,
List<Variable> inputVariables,
Variable outputVariable) {
List<Variable> outputVariables) {
fuzzyEngine.getRuleBlocks().clear();
fuzzyEngine.addRuleBlock(getRuleBlock(fuzzyEngine, rules, inputVariables, outputVariable));
fuzzyEngine.getInputVariables().clear();
fuzzyEngine.getOutputVariables().clear();
fuzzyEngine.addRuleBlock(getRuleBlock(fuzzyEngine, rules, inputVariables, outputVariables));
return getConsequent(fuzzyEngine, values);
}
public List<OutputValue> getProjectFuzzyInference(ProjectInferenceData projectInferenceData) {
List<String> fuzzyRules = projectRulesService.getByProjectId(projectInferenceData.getProjectId())
.stream()
.map(FuzzyRule::getContent)
.toList();
Map<String, Double> variableValues = projectInferenceData.getVariableValues()
.stream()
.collect(Collectors.toMap(
VariableValueDto::getVariableName,
VariableValueDto::getValue));
List<Variable> inputVariables = projectVariableService.getInputByProjectId(projectInferenceData.getProjectId());
List<Variable> outputVariables = projectVariableService.getOutputByProjectId(projectInferenceData.getProjectId());
return getFuzzyInference(fuzzyRules,
variableValues,
inputVariables,
outputVariables);
}
}

View File

@ -5,6 +5,7 @@ import ru.ulstu.fc.project.service.ProjectService;
import ru.ulstu.fc.rule.model.FuzzyTerm;
import ru.ulstu.fc.rule.model.Variable;
import ru.ulstu.fc.rule.model.VariableForm;
import ru.ulstu.fc.rule.model.dto.VariableDto;
import ru.ulstu.fc.rule.repository.VariableRepository;
import java.util.List;
@ -69,7 +70,28 @@ public class VariableService {
return variableRepository.getByProject(projectService.getById(projectId));
}
public List<VariableDto> getAllDtoByProject(Integer projectId) {
return variableRepository.getByProject(projectService.getById(projectId))
.stream()
.map(VariableDto::new)
.toList();
}
public void checkIsCurrentUserVariableWithThrow(Variable variable) {
projectService.checkIsCurrentUserProjectWithThrow(variable.getProject());
}
public List<VariableDto> getInputVariablesDtoByProject(Integer projectId) {
return variableRepository.getInputByProject(projectService.getById(projectId))
.stream()
.map(VariableDto::new)
.toList();
}
public List<VariableDto> getOutputVariablesDtoByProject(Integer projectId) {
return variableRepository.getOutputByProject(projectService.getById(projectId))
.stream()
.map(VariableDto::new)
.toList();
}
}

View File

@ -5,8 +5,7 @@ function getAntecedent(rule) {
return withoutIf[1].trim().split('then')[0].trim();
}
// TODO: remove duplicate
function getAntecedentComponents(antecedent) {
function getRuleComponents(antecedent) {
return antecedent.split('and').map((i) => i.trim());
}
@ -16,11 +15,6 @@ function getConsequent(rule) {
return withoutIf[1].trim().split('then')[1].trim();
}
// TODO: remove duplicate
function getConsequentComponents(consequent) {
return consequent.split('and').map((i) => i.trim());
}
// common
function getVariable(variableComponents) {
return variableComponents.split('is')[0].trim();
@ -56,8 +50,6 @@ function showFeedbackMessage(message, type) {
/* exported errorHandler */
function errorHandler(response, callBack, errorCallBack) {
if (!isEmpty(response.error)) {
// TODO: add l10n
// showFeedbackMessage(response.error.code + ": " + response.error.message, MessageTypesEnum.DANGER);
if (!isEmpty(errorCallBack)) {
errorCallBack(response.data);
}
@ -70,15 +62,12 @@ function errorHandler(response, callBack, errorCallBack) {
}
/* exported getFromRest */
function getFromRest(url, callBack) {
$.ajax({
async function getFromRest(url) {
return await $.ajax({
url: url,
method: 'get',
cache: true,
dataType: 'json',
success: function (response) {
errorHandler(response, callBack);
}
dataType: 'json'
});
}
@ -120,60 +109,63 @@ function fillSelect(selectElement, values, selectedVal) {
$(selectElement).append($("<option />").val(value.id).text(value.name));
});
$(selectElement).children().each(function () {
if ($(this).text() == selectedVal) {
if ($(this).text() === selectedVal) {
$(this).prop('selected', true);
}
});
}
function fillFuzzyTerms(variablesElement, fuzzyTermsElement, termVal) {
getFromRest("/rule/getFuzzyTerms/" + $(variablesElement).val(), function (fuzzyTerms) {
let fuzzyTermsData = [];
$.each(fuzzyTerms, function (key, value) {
fuzzyTermsData.push({
id: value.id,
name: value.description
});
async function fillFuzzyTerms(variablesElement, fuzzyTermsElement, termVal) {
let fuzzyTerms = await getFromRest("/rule/getFuzzyTerms/" + $(variablesElement).val());
let fuzzyTermsData = [];
$.each(fuzzyTerms, function (key, value) {
fuzzyTermsData.push({
id: value.id,
name: value.description
});
fillSelect(fuzzyTermsElement, fuzzyTermsData, termVal);
$(fuzzyTermsElement).selectpicker("refresh");
$(fuzzyTermsElement).trigger("change");
});
fillSelect(fuzzyTermsElement, fuzzyTermsData, termVal);
}
function fillVariables(projectId, variablesElement, variableVal) {
getFromRest("/rule/getVariables/" + projectId, function (variables) {
let variablesData = [];
$.each(variables, function (key, value) {
variablesData.push({
id: value.id,
name: value.name
});
async function fillVariables(projectId, variablesElement, variableVal, cls) {
let url = '/rule/';
if (cls === 'inputVar') {
url += 'getInputVariables/';
} else {
url += 'getOutputVariables/';
}
let variables = await getFromRest(url + projectId);
let variablesData = [];
$.each(variables, function (key, value) {
variablesData.push({
id: value.id,
name: value.name
});
fillSelect(variablesElement, variablesData, variableVal);
$(variablesElement).selectpicker("refresh");
$(variablesElement).trigger("change");
});
fillSelect(variablesElement, variablesData, variableVal);
}
function variableValueChanged(variablesElement, fuzzyTermsElement) {
fillFuzzyTerms(variablesElement, fuzzyTermsElement);
}
function fuzzyTermsValueChanged() {
async function variableValueChanged(variablesElement, fuzzyTermsElement) {
await fillFuzzyTerms(variablesElement, fuzzyTermsElement);
$(".selectpicker").selectpicker("refresh");
createRule();
}
function createVariableSelect(cls, projectId, variableVal) {
function fuzzyTermsValueChanged() {
$(".selectpicker").selectpicker("refresh");
createRule();
}
async function createVariableSelect(cls, projectId, variableVal) {
let variablesElement = $("<select class='selectpicker " + cls + " m-2' data-live-search='true data-width='70%'></select>");
fillVariables(projectId, variablesElement, variableVal);
await fillVariables(projectId, variablesElement, variableVal, cls);
return variablesElement;
}
function createFuzzyTermsSelect(cls, variablesElement, termVal) {
async function createFuzzyTermsSelect(cls, variablesElement, termVal) {
let fuzzyTermsElement = $("<select class='selectpicker " + cls + " m-2' data-live-search='true data-width='70%'></select>");
if ($(variablesElement).val()) {
fillFuzzyTerms(variablesElement, fuzzyTermsElement, termVal);
await fillFuzzyTerms(variablesElement, fuzzyTermsElement, termVal);
}
return fuzzyTermsElement;
}
@ -188,15 +180,15 @@ function removeConsequent(buttonElement) {
fuzzyTermsValueChanged();
}
function addAntecedent(parentElement, projectId, variableVal, termVal) {
async function addAntecedent(parentElement, projectId, variableVal, termVal) {
let rowElement = $("<div class='row'></div>");
if ($(parentElement).find('.row').length) {
$(rowElement).append("<label class='col col-md-1 m-2'>И</label>");
} else {
$(rowElement).append("<label class='col col-md-1 m-2'> </label>");
}
let variablesElement = createVariableSelect('inputVar', projectId, variableVal);
let fuzzyTermsElement = createFuzzyTermsSelect('inputVal', variablesElement, termVal);
let variablesElement = await createVariableSelect('inputVar', projectId, variableVal);
let fuzzyTermsElement = await createFuzzyTermsSelect('inputVal', variablesElement, termVal);
$(variablesElement).on("change", function () {
variableValueChanged(variablesElement, fuzzyTermsElement)
});
@ -210,19 +202,20 @@ function addAntecedent(parentElement, projectId, variableVal, termVal) {
$(rowElement).append("<a href='#' class='btn btn-outline-dark m-2' onclick='removeAntecedent($(this))'>-</a>");
}
$(parentElement).append(rowElement);
$(".selectpicker").selectpicker("refresh");
}
function addConsequent(parentElement, projectId, variableVal, termVal) {
async function addConsequent(parentElement, projectId, variableVal, termVal) {
let rowElement = $("<div class='row'></div>");
if ($(parentElement).find('.row').length) {
$(rowElement).append("<label class='col col-md-1 m-2'>И</label>");
} else {
$(rowElement).append("<label class='col col-md-1 m-2'> </label>");
}
let variablesElement = createVariableSelect('outVar', projectId, variableVal);
let fuzzyTermsElement = createFuzzyTermsSelect('outVal', variablesElement, termVal);
$(variablesElement).on("change", function () {
variableValueChanged(variablesElement, fuzzyTermsElement)
let variablesElement = await createVariableSelect('outVar', projectId, variableVal);
let fuzzyTermsElement = await createFuzzyTermsSelect('outVal', variablesElement, termVal);
$(variablesElement).on("change", async function () {
await variableValueChanged(variablesElement, fuzzyTermsElement)
});
$(fuzzyTermsElement).on("change", function () {
fuzzyTermsValueChanged()
@ -234,20 +227,34 @@ function addConsequent(parentElement, projectId, variableVal, termVal) {
$(rowElement).append("<a href='#' class='btn btn-outline-dark m-2' onclick='removeConsequent($(this))'>-</a>");
}
$(parentElement).append(rowElement);
$(".selectpicker").selectpicker("refresh");
}
function addAntecedentFromRule(parentElement, projectId, ruleContent) {
let antecedentComponents = getAntecedentComponents(getAntecedent(ruleContent));
async function addAntecedentFromRule(parentElement, projectId, ruleContent) {
let antecedentComponents = getRuleComponents(getAntecedent(ruleContent));
for (let i = 0; i < antecedentComponents.length; i++) {
let a = antecedentComponents[i];
addAntecedent(parentElement, projectId, getVariable(a), getVariableValue(a));
await addAntecedent(parentElement, projectId, getVariable(a), getVariableValue(a));
}
}
function addConsequentFromRule(parentElement, projectId, ruleContent) {
let consequentComponents = getConsequentComponents(getConsequent(ruleContent));
async function addConsequentFromRule(parentElement, projectId, ruleContent) {
let consequentComponents = getRuleComponents(getConsequent(ruleContent));
for (let i = 0; i < consequentComponents.length; i++) {
let c = consequentComponents[i];
addConsequent(parentElement, projectId, getVariable(c), getVariableValue(c));
await addConsequent(parentElement, projectId, getVariable(c), getVariableValue(c));
}
}
async function initSelects() {
let ruleContentEl = $('#ruleContent');
let projectIdEl = $('#projectId');
if ($(ruleContentEl).val()) {
await addAntecedentFromRule($('#rulesAntecedent'), $(projectIdEl).val(), $(ruleContentEl).val());
await addConsequentFromRule($('#rulesConsequent'), $(projectIdEl).val(), $(ruleContentEl).val());
} else {
await addAntecedent($('#rulesAntecedent'), $(projectIdEl).val());
await addConsequent($('#rulesConsequent'), $(projectIdEl).val());
}
$(".selectpicker").selectpicker("refresh");
}

View File

@ -11,7 +11,8 @@
<script type="text/javascript" src="/webjars/bootstrap-select/1.13.8/js/bootstrap-select.min.js"></script>
<link rel="stylesheet" href="/webjars/bootstrap/4.6.0/css/bootstrap.min.css"/>
<link rel="stylesheet" href="/webjars/bootstrap-select/1.13.8/css/bootstrap-select.min.css"/>
<link rel="stylesheet" href="/webjars/font-awesome/4.7.0/css/font-awesome.min.css"/>
<link rel="stylesheet" href="/webjars/bootstrap-icons/1.11.3/font/bootstrap-icons.min.css"/>
</head>
<body>

View File

@ -35,7 +35,13 @@
<div class="row" th:each="v, iter : ${variables}">
<div class="col col-md-12">
<a th:href="@{'/variable/edit/' + ${projectId}+'/'+${v.id}}">
<span class="badge badge-light" th:text="${iter.index+1} + '. ' + ${v.name}"></span>
<h3>
<span class="badge badge-light">
<span th:text="${iter.index+1} + '. ' + ${v.name}"></span>
<i th:if="${v.input}" class="bi bi-box-arrow-in-right"></i>
<i th:if="! ${v.input}" class="bi bi-box-arrow-right"></i>
</span>
</h3>
</a>
</div>
</div>
@ -48,7 +54,7 @@
<div class="row" th:each="r, iter : ${rules}">
<div class="col col-md-12">
<a th:href="@{'/rule/edit/' + ${projectId}+'/'+${r.id}}">
<div class="rule row" th:text="${r.content}"></div>
<div class="rule row d-none" th:text="${r.content}"></div>
</a>
</div>
</div>
@ -61,8 +67,8 @@
<script type="text/javascript">
function addRule(index, el, rule) {
let ruleHtml = "<div class='col col-md-12'><span class='badge badge-light'>" + (index + 1) + ". Если</span></div>"
let antecedentComponents = getAntecedentComponents(getAntecedent(rule));
let consequentComponents = getConsequentComponents(getConsequent(rule));
let antecedentComponents = getRuleComponents(getAntecedent(rule));
let consequentComponents = getRuleComponents(getConsequent(rule));
for (let i = 0; i < antecedentComponents.length; i++) {
let a = antecedentComponents[i];
if (i > 0) {
@ -70,9 +76,9 @@
} else {
ruleHtml += "<div class='col col-md-1'></div>";
}
ruleHtml += "<div class='col col-md-4'><span class='badge badge-primary'>"+getVariable(a)+"</span></div>";
ruleHtml += "<div class='col col-md-4'><span class='badge badge-primary'>" + getVariable(a) + "</span></div>";
ruleHtml += "<div class='col col-md-3'><span class='badge badge-light'>есть</span></div>";
ruleHtml += "<div class='col col-md-4'><span class='badge badge-success'>"+getVariableValue(a)+"</span></div>";
ruleHtml += "<div class='col col-md-4'><span class='badge badge-success'>" + getVariableValue(a) + "</span></div>";
}
ruleHtml += "<div class='col col-md-12'><span class='badge badge-light'>То</span></div>"
for (let i = 0; i < consequentComponents.length; i++) {
@ -87,11 +93,12 @@
ruleHtml += "<div class='col col-md-4'><span class='badge badge-success'>" + getVariableValue(c) + "</span></div>";
}
$(el).html(ruleHtml);
$(el).removeClass('d-none');
}
$('.rule').each(function(index) {
$('.rule').each(function (index) {
addRule(index, $(this), $(this).text());
});
</script>
</div>

View File

@ -7,16 +7,19 @@
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<div class="container" layout:fragment="content">
<a href="/project/edit/0" class="btn btn-outline-dark">
<i class="fa fa-plus-square" aria-hidden="true">Добавить проект</i>
</a>
<ul>
<li th:each="p : ${projects}">
<a th:href="@{'/project/edit/' + ${p.id}}">
<span th:text="${p.name} + ' от ' + ${#dates.format(p.createDate, 'dd.MM.yyyy HH:mm')}"></span>
</a>
</li>
</ul>
<div class="form-group">
<a href="/project/edit/0" class="btn btn-outline-dark">
<i class="bi bi-plus-square" aria-hidden="true"></i> Добавить проект
</a>
</div>
<div th:each="p : ${projects}">
<a th:href="@{'/project/edit/' + ${p.id}}">
<h3>
<span class="badge badge-light"
th:text="${p.name} + ' от ' + ${#dates.format(p.createDate, 'dd.MM.yyyy HH:mm')}">
</span>
</h3>
</a>
</div>
</div>
</html>

View File

@ -1,30 +0,0 @@
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-4.dtd">
<html xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
<title>Список правил</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<div class="container" layout:fragment="content">
<h3> Список правил</h3>
<div class="rowд">
<div class="col col-md-12">
<span class="badge badge-light">1. Если</span>
</div>
<div class="col col-md-3">
<span class="badge badge-primary">Переменная</span>
</div>
<div class="col col-md-3">
<span class="badge badge-light">есть</span>
</div>
<div class="col col-md-3">
<span class="badge badge-success">значение</span>
</div>
<div class="col col-md-3">
<span class="badge badge-danger">И / ИЛИ</span>
</div>
</div>
</div>
</html>

View File

@ -50,15 +50,9 @@
</div>
<script type="text/javascript" src="/js/fuzzyRule.js"></script>
<script type="text/javascript">
let ruleContentEl = $('#ruleContent');
let projectIdEl = $('#projectId');
if ($(ruleContentEl).val()) {
addAntecedentFromRule($('#rulesAntecedent'), $(projectIdEl).val(), $(ruleContentEl).val());
addConsequentFromRule($('#rulesConsequent'), $(projectIdEl).val(), $(ruleContentEl).val());
} else {
addAntecedent($('#rulesAntecedent'), $(projectIdEl).val());
addConsequent($('#rulesConsequent'), $(projectIdEl).val());
}
(async () => {
await initSelects();
})();
</script>
</form>
</div>

View File

@ -39,8 +39,10 @@
<div class="row" th:each="t, iter : ${fuzzyTerms}">
<div class="col col-md-12">
<a th:href="@{'/fuzzyTerm/edit/' + ${projectId} + '/' + ${variableId}+'/'+${t.id}}">
<span class="badge badge-light"
th:text="${iter.index+1} + '. ' + ${t.description}"></span>
<h3>
<span class="badge badge-light"
th:text="${iter.index+1} + '. ' + ${t.description}"></span>
</h3>
</a>
</div>
</div>