13-register #14

Merged
romanov73 merged 19 commits from 13-register into master 2025-02-18 14:17:09 +04:00
32 changed files with 612 additions and 145 deletions

2
.gitignore vendored
View File

@ -2,6 +2,8 @@
# Created by https://www.toptal.com/developers/gitignore/api/intellij,java,maven,gradle,eclipse,netbeans,node
# Edit at https://www.toptal.com/developers/gitignore?templates=intellij,java,maven,gradle,eclipse,netbeans,node
data/*
### Eclipse ###
.metadata
bin/

12
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,12 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "java",
"name": "FuzzyControllerApplication",
"request": "launch",
"mainClass": "ru.ulstu.fc.FuzzyControllerApplication",
"projectName": "fuzzy-controller"
}
]
}

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"java.configuration.updateBuildConfiguration": "interactive"
}

View File

@ -14,12 +14,12 @@ import ru.ulstu.fc.user.model.UserRoleConstants;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfiguration {
private final Logger log = LoggerFactory.getLogger(SecurityConfiguration.class);
private final String[] permittedUrls = new String[]{
"/login", "/index",
"/login", "/index", "/user/register",
"/public/**", "/organizers", "/webjars/**",
"/error", "/register",
"/h2-console/*", "/h2-console",
"/css/**", "/js/**", "/img/**",
"/templates/**", "/webjars/**"};

View File

@ -3,6 +3,7 @@ package ru.ulstu.fc.config;
import nz.net.ultraq.thymeleaf.layoutdialect.LayoutDialect;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.thymeleaf.extras.springsecurity6.dialect.SpringSecurityDialect;
import org.thymeleaf.spring6.SpringTemplateEngine;
import org.thymeleaf.templateresolver.ITemplateResolver;
@ -10,10 +11,11 @@ import org.thymeleaf.templateresolver.ITemplateResolver;
public class TemplateConfiguration {
@Bean
public SpringTemplateEngine templateEngine(ITemplateResolver templateResolver) {
public SpringTemplateEngine templateEngine(ITemplateResolver templateResolver, SpringSecurityDialect sec) {
final SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.addTemplateResolver(templateResolver);
templateEngine.addDialect(new LayoutDialect());
templateEngine.addDialect(sec);
return templateEngine;
}
}

View File

@ -10,18 +10,22 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import ru.ulstu.fc.project.model.Project;
import ru.ulstu.fc.project.model.ProjectForm;
import ru.ulstu.fc.project.service.ProjectRulesService;
import ru.ulstu.fc.project.service.ProjectService;
import ru.ulstu.fc.user.model.UserRoleConstants;
@Controller
@Hidden
@RequestMapping("project")
@Secured({UserRoleConstants.ADMIN})
@Secured({ UserRoleConstants.ADMIN })
public class ProjectController {
private final ProjectService projectService;
private final ProjectRulesService projectRulesService;
public ProjectController(ProjectService projectService) {
public ProjectController(ProjectService projectService,
ProjectRulesService projectRulesService) {
this.projectService = projectService;
this.projectRulesService = projectRulesService;
}
@GetMapping("list")
@ -36,6 +40,8 @@ public class ProjectController {
new ProjectForm((id != null && id != 0)
? projectService.getById(id)
: new Project()));
model.addAttribute("rules", projectRulesService.getByProjectId(id));
return "project/edit";
}

View File

@ -0,0 +1,12 @@
package ru.ulstu.fc.project.repository;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import ru.ulstu.fc.rule.model.Rule;
public interface RuleRepository extends JpaRepository<Rule, Integer> {
List<Rule> findByProjectId(Integer projectId);
}

View File

@ -0,0 +1,21 @@
package ru.ulstu.fc.project.service;
import java.util.List;
import org.springframework.stereotype.Service;
import ru.ulstu.fc.project.repository.RuleRepository;
import ru.ulstu.fc.rule.model.Rule;
@Service
public class ProjectRulesService {
private final RuleRepository ruleRepository;
public ProjectRulesService(RuleRepository ruleRepository) {
this.ruleRepository = ruleRepository;
}
public List<Rule> getByProjectId(Integer projectId) {
return ruleRepository.findByProjectId(projectId);
}
}

View File

@ -9,6 +9,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import ru.ulstu.fc.rule.model.Antecedent;
import ru.ulstu.fc.rule.model.InferenceForm;
import ru.ulstu.fc.rule.model.Variable;
import ru.ulstu.fc.rule.model.VariableValue;
import ru.ulstu.fc.rule.service.FuzzyInferenceService;
import java.util.Arrays;
@ -26,35 +28,38 @@ public class InferenceMvcController {
@GetMapping("/")
public String initInference(Model model) {
model.addAttribute("ageAntecedents", getAgeAntecedents());
model.addAttribute("incomeAntecedents", getIncomeAntecedents());
model.addAttribute("ageValues", getAgeValues());
model.addAttribute("incomeValues", getIncomeValues());
model.addAttribute("inferenceForm", new InferenceForm());
return "index";
}
@RequestMapping(value = "get-inference", method = RequestMethod.POST)
public String getInference(@ModelAttribute InferenceForm inferenceForm, Model model) {
model.addAttribute("ageAntecedents", getAgeAntecedents());
model.addAttribute("incomeAntecedents", getIncomeAntecedents());
model.addAttribute("ageValues", getAgeValues());
model.addAttribute("incomeValues", getIncomeValues());
model.addAttribute("inferenceForm", inferenceForm);
model.addAttribute("response", fuzzyInferenceService.getFuzzyInference(
Map.of("возраст", Double.valueOf(inferenceForm.getAgeAntecedent()),
"доход", Double.valueOf(inferenceForm.getIncomeAntecedent())
)));
Map.of("возраст", Double.valueOf(inferenceForm.getAgeValue()),
"доход", Double.valueOf(inferenceForm.getIncomeValue()))));
return "index";
}
private List<Antecedent> getAgeAntecedents() {
return Arrays.asList(
new Antecedent("молодой", "30"),
new Antecedent("средний", "45"),
new Antecedent("старый", "60"));
private List<VariableValue> getAgeValues() {
Variable var = new Variable("Age");
var.getValues().addAll(Arrays.asList(
new VariableValue("молодой", 30.0),
new VariableValue("средний", 45.0),
new VariableValue("старый", 60.0)));
return var.getValues();
}
private List<Antecedent> getIncomeAntecedents() {
return Arrays.asList(
new Antecedent("небольшой", "20000"),
new Antecedent("средний", "90000"),
new Antecedent("высокий", "200000"));
private List<VariableValue> getIncomeValues() {
Variable var = new Variable("Income");
var.getValues().addAll(Arrays.asList(
new VariableValue("небольшой", 20000.0),
new VariableValue("средний", 90000.0),
new VariableValue("высокий", 200000.0)));
return var.getValues();
}
}

View File

@ -0,0 +1,48 @@
package ru.ulstu.fc.rule.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import ru.ulstu.fc.rule.model.Rule;
import ru.ulstu.fc.rule.model.RuleForm;
import ru.ulstu.fc.rule.service.RuleService;
@Controller
@RequestMapping("rule")
public class RuleController {
private final RuleService ruleService;
public RuleController(RuleService ruleService) {
this.ruleService = ruleService;
}
@GetMapping("/edit/{projectId}/{ruleId}")
public String edit(@PathVariable(value = "projectId") Integer projectId,
@PathVariable(value = "ruleId") Integer id, Model model) {
model.addAttribute("projectId", projectId);
model.addAttribute("rule",
new RuleForm((id != null && id != 0)
? ruleService.getById(id)
: new Rule()));
return "rule/edit";
}
@PostMapping(value = "save", params = "save")
public String save(RuleForm ruleForm, Model model) {
model.addAttribute("rule", ruleService.save(ruleForm));
return "redirect:/project/edit/" + ruleForm.getProjectId();
}
@PostMapping(value = "save", params = "delete")
public String delete(RuleForm ruleForm) {
if (ruleForm != null && ruleForm.getId() != null) {
ruleService.delete(ruleForm);
}
return "redirect:/project/edit/" + ruleForm.getProjectId();
}
}

View File

@ -1,19 +1,25 @@
package ru.ulstu.fc.rule.model;
public class Antecedent {
import jakarta.persistence.Entity;
import jakarta.persistence.ManyToOne;
import ru.ulstu.fc.core.model.BaseEntity;
@Entity
public class Antecedent extends BaseEntity {
@ManyToOne
private Variable variable;
private String value;
private String description;
public Antecedent(String description, String value) {
this.description = description;
this.value = value;
public Variable getVariable() {
return variable;
}
public void setVariable(Variable variable) {
this.variable = variable;
}
public String getValue() {
return value;
}
public String getDescription() {
return description;
public void setValue(String value) {
this.value = value;
}
}

View File

@ -0,0 +1,29 @@
package ru.ulstu.fc.rule.model;
import jakarta.persistence.Entity;
import jakarta.persistence.ManyToOne;
import ru.ulstu.fc.core.model.BaseEntity;
@Entity
public class Consequent extends BaseEntity {
@ManyToOne
private Variable variable;
private String value;
public Variable getVariable() {
return variable;
}
public void setVariable(Variable variable) {
this.variable = variable;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}

View File

@ -1,22 +1,22 @@
package ru.ulstu.fc.rule.model;
public class InferenceForm {
private String ageAntecedent;
private String incomeAntecedent;
private String ageValue;
private String incomeValue;
public String getAgeAntecedent() {
return ageAntecedent;
public String getAgeValue() {
return ageValue;
}
public void setAgeAntecedent(String ageAntecedent) {
this.ageAntecedent = ageAntecedent;
public void setAgeValue(String ageAntecedent) {
this.ageValue = ageAntecedent;
}
public String getIncomeAntecedent() {
return incomeAntecedent;
public String getIncomeValue() {
return incomeValue;
}
public void setIncomeAntecedent(String incomeAntecedent) {
this.incomeAntecedent = incomeAntecedent;
public void setIncomeValue(String incomeAntecedent) {
this.incomeValue = incomeAntecedent;
}
}

View File

@ -0,0 +1,47 @@
package ru.ulstu.fc.rule.model;
import java.util.List;
import jakarta.persistence.Entity;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import ru.ulstu.fc.core.model.BaseEntity;
import ru.ulstu.fc.project.model.Project;
@Entity
public class Rule extends BaseEntity {
@ManyToOne
private Project project;
@OneToMany
private List<Antecedent> antecedents; //TODO: AND / OR?
@ManyToOne
private Consequent consequent;
public Rule() {
}
public Project getProject() {
return project;
}
public void setProject(Project project) {
this.project = project;
}
public List<Antecedent> getAntecedents() {
return antecedents;
}
public void setAntecedents(List<Antecedent> antecedents) {
this.antecedents = antecedents;
}
public Consequent getConsequent() {
return consequent;
}
public void setConsequent(Consequent consequent) {
this.consequent = consequent;
}
}

View File

@ -0,0 +1,32 @@
package ru.ulstu.fc.rule.model;
public class RuleForm {
private Integer id;
private Integer projectId;
public RuleForm() {
}
public RuleForm(Rule rule) {
this.projectId = (rule == null || rule.getProject() == null)
? null
: rule.getProject().getId();
}
public Integer getProjectId() {
return projectId;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public void setProjectId(Integer projectId) {
this.projectId = projectId;
}
}

View File

@ -1,10 +1,17 @@
package ru.ulstu.fc.rule.model;
import java.util.ArrayList;
import java.util.List;
public class Variable {
import jakarta.persistence.Entity;
import jakarta.persistence.OneToMany;
import ru.ulstu.fc.core.model.BaseEntity;
@Entity
public class Variable extends BaseEntity {
private String name;
private List<VariableValue> values;
@OneToMany
private List<VariableValue> values = new ArrayList<>();
public Variable() {
}
@ -14,6 +21,10 @@ public class Variable {
this.values = values;
}
public Variable(String name) {
this.name = name;
}
public String getName() {
return name;
}

View File

@ -1,6 +1,10 @@
package ru.ulstu.fc.rule.model;
public class VariableValue {
import jakarta.persistence.Entity;
import ru.ulstu.fc.core.model.BaseEntity;
@Entity
public class VariableValue extends BaseEntity {
private String fuzzyTerm;
private Double value;

View File

@ -0,0 +1,43 @@
package ru.ulstu.fc.rule.service;
import org.springframework.stereotype.Service;
import ru.ulstu.fc.project.repository.RuleRepository;
import ru.ulstu.fc.project.service.ProjectService;
import ru.ulstu.fc.rule.model.Rule;
import ru.ulstu.fc.rule.model.RuleForm;
@Service
public class RuleService {
private final RuleRepository ruleRepository;
private final ProjectService projectService;
public RuleService(RuleRepository ruleRepository, ProjectService projectService) {
this.ruleRepository = ruleRepository;
this.projectService = projectService;
}
public Rule getById(Integer id) {
return ruleRepository
.findById(id)
.orElseThrow(() -> new RuntimeException("Rule not found by id"));
}
public Object save(RuleForm ruleForm) {
if (ruleForm.getId() == null) {
Rule rule = new Rule();
rule.setProject(projectService.getById(ruleForm.getProjectId()));
// rule.set...
return ruleRepository.save(rule);
}
Rule dbRule = getById(ruleForm.getId());
dbRule.setProject(projectService.getById(ruleForm.getProjectId()));
// dbRule.set ...
return ruleRepository.save(dbRule);
}
public void delete(RuleForm ruleForm) {
getById(ruleForm.getId());
ruleRepository.deleteById(ruleForm.getId());
}
}

View File

@ -0,0 +1,42 @@
package ru.ulstu.fc.user.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.ModelAndView;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import ru.ulstu.fc.user.model.User;
import ru.ulstu.fc.user.model.UserDto;
import ru.ulstu.fc.user.service.UserService;
@Controller
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping("/user/register")
public String showRegistrationForm(WebRequest request, Model model) {
UserDto userDto = new UserDto();
model.addAttribute("user", userDto);
return "register";
}
@PostMapping("/user/register")
public String registerUserAccount(
@ModelAttribute("user") @Valid UserDto userDto,
HttpServletRequest request,
Errors errors) {
userService.createUser(new User(userDto));
return "redirect:/login";
}
}

View File

@ -6,6 +6,7 @@ import jakarta.persistence.JoinColumn;
import jakarta.persistence.JoinTable;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.Table;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
@ -46,6 +47,11 @@ public class User extends BaseEntity {
this.roles = roles;
}
public User(UserDto userDto) {
this.login = userDto.getLogin();
this.password = userDto.getPassword();
}
public String getLogin() {
return login;
}

View File

@ -0,0 +1,40 @@
package ru.ulstu.fc.user.model;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
public class UserDto {
@NotNull
@NotEmpty
private String login;
@NotNull
@NotEmpty
private String password;
private String matchingPassword;
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getMatchingPassword() {
return matchingPassword;
}
public void setMatchingPassword(String matchingPassword) {
this.matchingPassword = matchingPassword;
}
}

View File

@ -7,6 +7,8 @@ logging.level.ru.ulstu=DEBUG
logging.level.sun.rmi.transport=off
logging.level.javax.management.remote.rmi=off
logging.level.java.rmi.server=off
logging.level.org.apache.tomcat=INFO
logging.level.org.apache.tomcat.util.net=WARN
extractor.custom-projects-dir=
server.error.include-stacktrace=always
server.error.include-exception=true

View File

@ -1,57 +1,71 @@
<!DOCTYPE html>
<html lang="ru"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:th="http://www.w3.org/1999/xhtml">
<html lang="ru" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity6">
<head>
<meta charset="UTF-8"/>
<meta charset="UTF-8" />
<title>Нечеткий контроллер</title>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script type="text/javascript" src="/webjars/jquery/3.6.0/jquery.min.js"></script>
<script type="text/javascript" src="/webjars/bootstrap/4.6.0/js/bootstrap.bundle.min.js"></script>
<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/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" />
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light" layout:fragment="navbar">
<a class="navbar-brand" href="/">Нечеткий контроллер</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">Проекты</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="/project/list">Список проектов</a>
</div>
</li>
<li class="nav-item">
<a class="nav-link" href="/swagger-ui/index.html">API</a>
</li>
</ul>
</div>
</nav>
<div class="wrapper">
<div id="sidebar" class="collapse navbar-collapse sidebar-mobile">
<ul id="menu" class="list-unstyled">
</ul>
</div>
<div id="content">
<div id="breadcrumbs" class="container-fluid">
</div>
<div class="container-fluid">
<ul id="messages" class="feedback-panel">
<div class="alert alert-danger" role="alert" th:if="${error}" th:text="${error}">
</div>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light" layout:fragment="navbar">
<a class="navbar-brand" href="/">Нечеткий контроллер</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">Проекты</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="/project/list">Список проектов</a>
</div>
</li>
<li class="nav-item">
<a class="nav-link" href="/swagger-ui/index.html">API</a>
</li>
<li>
<div sec:authorize="isAuthenticated()">
<a class="nav-link" href="/logout">
<span sec:authentication="name">Bob</span>
(Выход)</a>
</div>
<div sec:authorize="!isAuthenticated()">
<a class="nav-link" href="/login">Вход</a>
</div>
</li>
</ul>
</div>
<div layout:fragment="content">
</nav>
<div class="wrapper">
<div id="sidebar" class="collapse navbar-collapse sidebar-mobile">
<ul id="menu" class="list-unstyled">
</ul>
</div>
<div id="content">
<div id="breadcrumbs" class="container-fluid">
</div>
<div class="container-fluid">
<ul id="messages" class="feedback-panel">
<div class="alert alert-danger" role="alert" th:if="${error}" th:text="${error}">
</div>
</ul>
</div>
<div layout:fragment="content">
</div>
</div>
</div>
</div>
</body>
</html>

View File

@ -25,11 +25,11 @@
</div>
<div class="col-md-6 col-sm-12">
<select id="select-age-antecedent" class="selectpicker m-2" data-live-search="true"
th:field="*{ageAntecedent}"
th:field="*{ageValue}"
data-width="90%">
<option th:each="ageAntecedent : ${ageAntecedents}"
th:value="${ageAntecedent.value}"
th:utext="${ageAntecedent.description}">
<option th:each="ageValue : ${ageValues}"
th:value="${ageValue.value}"
th:utext="${ageValue.fuzzyTerm}">
</option>
</select>
</div>
@ -40,11 +40,11 @@
</div>
<div class="col-md-6 col-sm-12">
<select id="select-income-antecedent" class="selectpicker m-2" data-live-search="true"
th:field="*{incomeAntecedent}"
th:field="*{incomeValue}"
data-width="90%">
<option th:each="incomeAntecedent : ${incomeAntecedents}"
th:value="${incomeAntecedent.value}"
th:utext="${incomeAntecedent.description}">
<option th:each="incomeValue : ${incomeValues}"
th:value="${incomeValue.value}"
th:utext="${incomeValue.fuzzyTerm}">
</option>
</select>
</div>

View File

@ -1,42 +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" xmlns:th="http://www.w3.org/1999/xhtml"
layout:decorate="~{default}">
<head>
<title>Список правил</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<div class="container" layout:fragment="content">
<table class="table table-striped">
<thead class="thead-dark">
<tr>
<th scope="col" colspan="10">Правила</th>
</tr>
</thead>
<tbody>
<tr th:each="dbRule: ${rules}">
<td><span class="badge badge-info">Если</span></td>
<td><span class="badge badge-success" th:text="${dbRule.firstAntecedent.description}"></span></td>
<td><span class="badge badge-success" th:text="${dbRule.firstAntecedentValue.antecedentValue}"></span></td>
<td><span class="badge badge-info">и</span></td>
<td><span class="badge badge-success" th:text="${dbRule.secondAntecedent.description }"></span></td>
<td><span class="badge badge-success" th:text="${dbRule.secondAntecedentValue.antecedentValue}"></span></td>
<td><span class="badge badge-info">то</span></td>
<td><span class="badge badge-warning" th:text="${dbRule.consequent}"></span></td>
<td>
<a role="button" class="btn btn-info" th:href="@{${@route.ADD_RULE} + '?ruleId=' + ${dbRule.id}}">
<i class="fa fa-pencil-square-o" aria-hidden="true"></i>
</a>
</td>
<td>
<a role="button" class="btn btn-danger" th:href="@{'deleteRule?id=' + ${dbRule.id}}"
onclick="return confirm('Удалить правило?')">
<i class="fa fa-times" aria-hidden="true"></i>
</a>
</td>
</tr>
</tbody>
</table>
<a href="/addRule" class="btn btn-outline-success">Добавить правило</a>
</div>
</html>

View File

@ -24,7 +24,8 @@
<input type="password" name="password" id="password" class="form-control"
placeholder="Пароль" required="true"/>
</div>
<button type="submit" class="btn btn-outline-dark btn-block">Войти</button>
<button type="submit" class="btn btn-outline-dark">Войти</button>
<a href="/user/register" class="btn btn-outline-dark">Регистрация</a>
</fieldset>
</form>
</div>

View File

@ -6,12 +6,11 @@
<head>
</head>
<body>
<nav layout:fragment="navbar">
<div class="navbar-header">
<a class="navbar-brand" href="/"><span class="ui-menuitem-text"><i
class="fa fa-plane fa-4" aria-hidden="true"></i> Balance</span></a>
</div>
</nav>
<nav layout:fragment="navbar">
<div class="navbar-header">
<a class="navbar-brand" href="/"><span class="ui-menuitem-text">Нечеткий контроллер</span></a>
</div>
</nav>
<div class="container" layout:fragment="content">
<div class="container-fluid">
<ul id="messages" class="feedback-panel">

View File

@ -35,5 +35,39 @@
</button>
<a href="/project/list" class="btn btn-outline-dark">Отмена</a>
</form>
<hr/>
<h4> Список правил</h4>
<div class="row" th:each="r, iter : ${rules}">
<div class="col col-md-12">
<span class="badge badge-light" th:text="${iter} + ' Если'"></span>
</div>
<div class="col col-md-2 offset-md-3">
<span class="badge badge-primary">Переменная</span>
</div>
<div class="col col-md-2">
<span class="badge badge-light">есть</span>
</div>
<div class="col col-md-2">
<span class="badge badge-success">значение</span>
</div>
<div class="col col-md-1">
<span class="badge badge-danger">И / ИЛИ</span>
</div>
<div class="col col-md-2 offset-md-3">
<span class="badge badge-primary">Переменная</span>
</div>
<div class="col col-md-2">
<span class="badge badge-light">есть</span>
</div>
<div class="col col-md-2">
<span class="badge badge-success">значение</span>
</div>
<div class="col col-md-1">
<span class="badge badge-danger">И / ИЛИ</span>
</div>
</div>
<a th:href="@{'/rule/edit/' + ${projectId}+'/0'}" class="btn btn-outline-dark">Добавить правило</a>
</div>
</html>

View File

@ -3,7 +3,7 @@
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:th="http://www.w3.org/1999/xhtml"
layout:decorate="~{default}">
<head>
<title>Список правил</title>
<title>Список проектов</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<div class="container" layout:fragment="content">

View File

@ -0,0 +1,30 @@
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-4.dtd">
<html xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:th="http://www.w3.org/1999/xhtml"
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

@ -0,0 +1,29 @@
<!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}">
<div class="container" layout:fragment="content">
<h3>Регистрация</h3>
<form action="/user/register" th:object="${user}" method="POST" enctype="utf8">
<div class="form-group">
<label for="login">Логин</label>
<input th:field="*{login}" id="login" type="text" required class="form-control"
placeholder="Логин пользователя">
<p th:each="error: ${#fields.errors('login')}" th:text="${error}">Validation error</p>
</div>
<div class="form-group">
<label for="password">Пароль</label>
<input th:field="*{password}" id="password" type="text" required class="form-control"
placeholder="Пароль">
<p th:each="error : ${#fields.errors('password')}" th:text="${error}">Validation error</p>
</div>
<div class="form-group">
<label for="confirmPass">Подтверждение пароля</label>
<input id = "confirmPass" type="password" th:field="*{matchingPassword}" required class="form-control"
placeholder="Подтверждение пароля"/>
</div>
<button type="submit" class="btn btn-outline-dark">Зарегистрировать</button>
<a href="/login" class="btn btn-outline-dark">Вернуться на страницу входа</a>
</form>
</div>
</body>
</html>

View File

@ -0,0 +1,29 @@
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-4.dtd">
<html
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:th="http://www.w3.org/1999/xhtml"
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>
<form th:action="@{/rule/save}" th:object="${rule}" method="post">
<input type="hidden" th:field="${projectId}">
<input type="hidden" th:field="*{id}">
<div class="form-group">
<label for="name">Название</label>
</div>
<button name="save" type="submit" class="btn btn-outline-dark">Сохранить</button>
<button name="delete"
type="submit"
class="btn btn-outline-dark"
onclick="return confirm('Удалить запись?')">
Удалить
</button>
<a th:href="@{'/project/edit/' + ${projectId}}" class="btn btn-outline-dark">Отмена</a>
</form>
</div>
</html>