Compare commits

...

2 Commits

Author SHA1 Message Date
esoe e24cf5bd40 qq 2 weeks ago
esoe ff3e485a76 qq 2 weeks ago
  1. 75
      main/src/main/java/gsp/technologies/main/account/AccountController.java
  2. 22
      main/src/main/java/gsp/technologies/main/account/dto/AccountDTO.java
  3. 17
      main/src/main/java/gsp/technologies/main/account/dto/OrganizationDTO.java
  4. 18
      main/src/main/java/gsp/technologies/main/account/dto/PositionDTO.java
  5. 36
      main/src/main/java/gsp/technologies/main/api/account/AccountEntity.java
  6. 134
      main/src/main/java/gsp/technologies/main/api/account/AccountFaceController.java
  7. 9
      main/src/main/java/gsp/technologies/main/api/account/AccountRepository.java
  8. 20
      main/src/main/java/gsp/technologies/main/api/account/AccountService.java
  9. 24
      main/src/main/java/gsp/technologies/main/api/course/CourseEntity.java
  10. 53
      main/src/main/java/gsp/technologies/main/api/course/CourseFaceController.java
  11. 9
      main/src/main/java/gsp/technologies/main/api/course/CourseRepository.java
  12. 23
      main/src/main/java/gsp/technologies/main/api/course/CourseService.java
  13. 77
      main/src/main/java/gsp/technologies/main/api/organization/OrganizationFaceController.java
  14. 8
      main/src/main/java/gsp/technologies/main/api/organization/OrganizationService.java
  15. 11
      main/src/main/java/gsp/technologies/main/api/position/PositionApiController.java
  16. 3
      main/src/main/java/gsp/technologies/main/api/position/PositionEntity.java
  17. 79
      main/src/main/java/gsp/technologies/main/api/position/PositionFaceController.java
  18. 4
      main/src/main/java/gsp/technologies/main/api/position/PositionRepository.java
  19. 16
      main/src/main/java/gsp/technologies/main/api/position/PositionService.java
  20. 8
      main/src/main/java/gsp/technologies/main/api/quiz/QuizController.java
  21. 46
      main/src/main/java/gsp/technologies/main/api/target/TargetEntity.java
  22. 91
      main/src/main/java/gsp/technologies/main/api/target/TargetFaceController.java
  23. 9
      main/src/main/java/gsp/technologies/main/api/target/TargetRepository.java
  24. 34
      main/src/main/java/gsp/technologies/main/api/target/TargetService.java
  25. 36
      main/src/main/java/gsp/technologies/main/course/CourseController.java
  26. 19
      main/src/main/java/gsp/technologies/main/course/dto/CourseDTO.java
  27. 37
      main/src/main/java/gsp/technologies/main/mainframe/MainframeController.java
  28. 2
      main/src/main/resources/templates/account.html
  29. 6
      main/src/main/resources/templates/course.html
  30. 58
      main/src/main/resources/templates/courses/fragments/main.html
  31. 25
      main/src/main/resources/templates/courses/main.html
  32. 26
      main/src/main/resources/templates/error.html
  33. 7
      main/src/main/resources/templates/fragments/account.html
  34. 39
      main/src/main/resources/templates/fragments/controls.html
  35. 34
      main/src/main/resources/templates/mainframe.html
  36. 23
      main/src/main/resources/templates/organizations/edit.html
  37. 57
      main/src/main/resources/templates/organizations/fragments/main.html
  38. 10
      main/src/main/resources/templates/organizations/main.html
  39. 64
      main/src/main/resources/templates/positions/fragments/main.html
  40. 25
      main/src/main/resources/templates/positions/main.html
  41. 104
      main/src/main/resources/templates/targets/fragments/main.html
  42. 56
      main/src/main/resources/templates/targets/main.html

75
main/src/main/java/gsp/technologies/main/account/AccountController.java

@ -1,75 +0,0 @@
package gsp.technologies.main.account;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.request.RequestContextHolder;
import gsp.technologies.main.account.dto.AccountDTO;
import gsp.technologies.main.course.dto.CourseDTO;
import gsp.technologies.main.account.dto.OrganizationDTO;
import gsp.technologies.main.account.dto.PositionDTO;
import gsp.technologies.main.code.Code;
/**
* Контроллер формы аккаунта
* возвращает thymeleaf шаблон
*/
@Controller
@RequestMapping(path = "/account")
public class AccountController {
private static final Logger log = LoggerFactory.getLogger(AccountController.class);
@GetMapping("")
public String account(Model model) {
log.info("GET /account");
//данные аккаунта (id, organization, position)
String id = 1 + "";
String code = Code.encode(id);
OrganizationDTO organization = OrganizationDTO.builder()
.id(1 + "")
.name("ГСП-Т")
.build();
PositionDTO position = PositionDTO.builder()
.id(1 + "")
.name("Сварщик")
.organization(organization)
.build();
String sessionid = RequestContextHolder.currentRequestAttributes().getSessionId();
List<CourseDTO> courses = List.of(
CourseDTO.builder()
.id(1 + "")
.name("Охрана труда")
.passed(true)
.build(),
CourseDTO.builder()
.id(2 + "")
.name("Работы на высоте")
.passed(false)
.build(),
CourseDTO.builder()
.id(3 + "")
.name("Первая помощь")
.passed(true)
.build()
);
AccountDTO account = AccountDTO.builder()
.id(id)
.code(code)
.position(position)
.sessionid(sessionid)
.courses(courses)
.build();
// log.info("account: {}", account);
model.addAttribute("account", account);
log.info("Акаунт добавлен в модель: {}", account);
return "account";
}
}

22
main/src/main/java/gsp/technologies/main/account/dto/AccountDTO.java

@ -1,22 +0,0 @@
package gsp.technologies.main.account.dto;
import java.io.Serializable;
import java.util.List;
import gsp.technologies.main.course.dto.CourseDTO;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Data
public class AccountDTO implements Serializable {
private String id;
private String code;
private PositionDTO position;
private String sessionid;
private List<CourseDTO> courses;
}

17
main/src/main/java/gsp/technologies/main/account/dto/OrganizationDTO.java

@ -1,17 +0,0 @@
package gsp.technologies.main.account.dto;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Data
public class OrganizationDTO implements Serializable {
private String id;
private String name; //наименование организации
}

18
main/src/main/java/gsp/technologies/main/account/dto/PositionDTO.java

@ -1,18 +0,0 @@
package gsp.technologies.main.account.dto;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Data
public class PositionDTO implements Serializable {
private String id;
private String name;
private OrganizationDTO organization;
}

36
main/src/main/java/gsp/technologies/main/api/account/AccountEntity.java

@ -0,0 +1,36 @@
package gsp.technologies.main.api.account;
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;
import gsp.technologies.main.api.position.PositionEntity;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Entity
public class AccountEntity {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String code;
@ManyToOne(fetch = FetchType.EAGER, optional = false)
@JoinColumn(name = "position", referencedColumnName = "id")
@OnDelete(action = OnDeleteAction.CASCADE)
private PositionEntity position;
}

134
main/src/main/java/gsp/technologies/main/api/account/AccountFaceController.java

@ -0,0 +1,134 @@
package gsp.technologies.main.api.account;
import java.util.Collection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import gsp.technologies.main.api.course.CourseEntity;
import gsp.technologies.main.api.organization.OrganizationService;
import gsp.technologies.main.api.position.PositionEntity;
import gsp.technologies.main.api.position.PositionService;
import gsp.technologies.main.api.target.TargetEntity;
import gsp.technologies.main.api.target.TargetService;
import gsp.technologies.main.code.Code;
/**
* Контроллер формы аккаунта
* возвращает thymeleaf шаблон
*/
@Controller
@RequestMapping(path = "/account")
public class AccountFaceController {
private static final Logger log = LoggerFactory.getLogger(AccountFaceController.class);
@Autowired
private OrganizationService organizationService;
@Autowired
private PositionService positionService;
@Autowired
private AccountService accountService;
@Autowired
private TargetService targetService;
public AccountFaceController(
PositionService positionService
, OrganizationService organizationService
, AccountService accountService
, TargetService targetService
) {
this.positionService = positionService;
this.organizationService = organizationService;
this.accountService = accountService;
this.targetService = targetService;
}
/**
* Форма аккаунта:
* - данные аккаунта (id, organization, position)
* - список курсов аккаунта
*
* @param model
* @param accountid
* @param positionid
* @return
*/
@GetMapping("")
public String account(Model model,
@RequestParam(name = "accountid", required = false) String accountid,
@RequestParam(name = "positionid", required = false) String positionid
) {
log.info("GET /account");
//данные аккаунта (id, organization, position)
log.info("accountid: " + accountid);
log.info("positionid: " + positionid);
if (accountid != null) {
log.info("accountid: " + accountid);
try{
//передаем в модель данные аккаунта
AccountEntity account = accountService.findById(Long.valueOf(accountid));
model.addAttribute("account", account);
//передаем в модель перечень доступных курсов
Collection<TargetEntity> targets = targetService.findAllByPositionId(account.getPosition().getId());
Collection<CourseEntity> courses = targetService.findAllByPosition(account.getPosition());
model.addAttribute("courses", courses);
//передаем в модель статусы прохождения курсов
return "account";
} catch (Exception e) {
StringBuilder msg = new StringBuilder();
msg.append("Не удалось получить данные аккаунта: " + e.getMessage());
log.error(msg.toString());
model.addAttribute("error", msg.toString());
return "error";
}
}
if (positionid != null) {
try{
log.info("positionid: " + positionid);
PositionEntity position = positionService.findById(Long.valueOf(positionid));
//обработать вход нового пользователя
AccountEntity account = AccountEntity.builder()
.position(position)
.build();
//сохранить в базе данных
account = accountService.save(account);
log.info("сохраняем account: " + account);
//получить id аккаунта
String code = Code.encode(account.getId() + "");
account.setCode(code);
//обновили аккаунт в базе данных
account = accountService.save(account);
model.addAttribute("account", account);
return "account";
} catch (Exception e) {
StringBuilder msg = new StringBuilder();
msg.append("Не удалось получить данные аккаунта: " + e.getMessage());
log.error(msg.toString());
model.addAttribute("error", msg.toString());
return "error";
}
}
//вернуть страницу ошибки
StringBuilder msg = new StringBuilder();
msg.append("Не указаны данные для доступа к аккаунту.");
log.error(msg.toString());
model.addAttribute("error", msg.toString());
return "error";
}
}

9
main/src/main/java/gsp/technologies/main/api/account/AccountRepository.java

@ -0,0 +1,9 @@
package gsp.technologies.main.api.account;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface AccountRepository extends JpaRepository<AccountEntity, Long> {
}

20
main/src/main/java/gsp/technologies/main/api/account/AccountService.java

@ -0,0 +1,20 @@
package gsp.technologies.main.api.account;
import org.springframework.stereotype.Service;
@Service
public class AccountService {
private final AccountRepository repo;
public AccountService(AccountRepository repo) {
this.repo = repo;
}
public AccountEntity save(AccountEntity account) {
return repo.save(account);
}
public AccountEntity findById(Long id) {
return repo.findById(id).orElse(null);
}
}

24
main/src/main/java/gsp/technologies/main/api/course/CourseEntity.java

@ -0,0 +1,24 @@
package gsp.technologies.main.api.course;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Entity
public class CourseEntity {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String name;
}

53
main/src/main/java/gsp/technologies/main/api/course/CourseFaceController.java

@ -0,0 +1,53 @@
package gsp.technologies.main.api.course;
import java.util.Collection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.PostMapping;
@Controller
@RequestMapping(path = "/courses")
public class CourseFaceController {
private static final Logger log = LoggerFactory.getLogger(CourseFaceController.class);
@Autowired
private CourseService courseService;
public CourseFaceController(CourseService courseService) {
this.courseService = courseService;
}
@GetMapping("")
public String course(Model model) {
log.info("GET /courses");
Collection <CourseEntity> courses = courseService.findAll();
model.addAttribute("courses", courses);
return "courses/main";
}
/**
* Создание нового курса
*/
@PostMapping("")
public String create(@RequestParam(name = "name", required = true) String name) {
log.info("POST /courses");
CourseEntity entity = new CourseEntity();
entity.setName(name);
courseService.save(entity);
return "redirect:/courses";
}
}

9
main/src/main/java/gsp/technologies/main/api/course/CourseRepository.java

@ -0,0 +1,9 @@
package gsp.technologies.main.api.course;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface CourseRepository extends JpaRepository<CourseEntity, Long> {
}

23
main/src/main/java/gsp/technologies/main/api/course/CourseService.java

@ -0,0 +1,23 @@
package gsp.technologies.main.api.course;
import java.util.Collection;
import org.springframework.stereotype.Service;
@Service
public class CourseService {
private final CourseRepository repo;
public CourseService(CourseRepository repo) {
this.repo = repo;
}
public Collection<CourseEntity> findAll() {
return repo.findAll();
}
public CourseEntity save(CourseEntity entity) {
return repo.save(entity);
}
public CourseEntity findById(Long courseid) {
return repo.findById(courseid).get();
}
}

77
main/src/main/java/gsp/technologies/main/api/organization/OrganizationFaceController.java

@ -1,23 +1,98 @@
package gsp.technologies.main.api.organization; package gsp.technologies.main.api.organization;
import java.util.Collection;
import java.util.stream.Collectors;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.PostMapping;
@Controller @Controller
@RequestMapping(path = "/organizations") @RequestMapping(path = "/organizations")
public class OrganizationFaceController { public class OrganizationFaceController {
private static final Logger log = LoggerFactory.getLogger(OrganizationFaceController.class); private static final Logger log = LoggerFactory.getLogger(OrganizationFaceController.class);
@Autowired
private OrganizationService service;
public OrganizationFaceController(OrganizationService organizationService) {
this.service = organizationService;
}
/** /**
* Главная страница для работы с перечнем организаций * Главная страница для работы с перечнем организаций
* @return * @return
*/ */
@GetMapping("") @GetMapping("")
public String organizations() { public String organizations(Model model) {
log.info("GET /organizations"); log.info("GET /organizations");
// получаем список организаций
Collection<OrganizationEntity> organizations = service.findAll();
// сортируем по названию
organizations = organizations.stream().sorted((o1, o2) -> o1.getName().compareTo(o2.getName())).collect(Collectors.toList());
// передаем список организаций в шаблон
model.addAttribute("organizations", organizations);
model.addAttribute("organizationService", service);
return "organizations/main"; return "organizations/main";
} }
/**
* Добавление новой организации
*/
@PostMapping("")
public String create(@RequestParam(name = "name", required = true) String name) {
log.info("POST /organizations");
OrganizationEntity entity = new OrganizationEntity();
entity.setName(name);
service.save(entity);
return "redirect:/organizations";
}
/**
* Удаление организации
* @param id
*/
@GetMapping("/{id}/delete")
public String delete(@PathVariable(name = "id", required = true) Long id) {
log.info("GET /organizations/{id}/delete");
service.deleteById(id);
return "redirect:/organizations";
}
/**
* Переход к форме редактирования организации
*/
@GetMapping("/{id}/edit")
public String edit(@PathVariable(name = "id", required = true) Long id, Model model) {
log.info("GET /organizations/{id}/edit");
OrganizationEntity entity = service.findById(id);
model.addAttribute("organization", entity);
return "organizations/edit";
}
/**
* Редакрирование организации
*/
@PostMapping("/{id}/edit")
public String update(@PathVariable(name = "id", required = true) Long id, @RequestParam(name = "name", required = true) String name) {
log.info("POST /organizations/{id}/edit");
OrganizationEntity entity = new OrganizationEntity();
entity.setName(name);
entity.setId(id);
service.save(entity);
return "redirect:/organizations";
}
} }

8
main/src/main/java/gsp/technologies/main/api/organization/OrganizationService.java

@ -19,4 +19,12 @@ public class OrganizationService {
public OrganizationEntity save(OrganizationEntity organization) { public OrganizationEntity save(OrganizationEntity organization) {
return repo.save(organization); return repo.save(organization);
} }
public void deleteById(Long id) {
repo.deleteById(id);
}
public OrganizationEntity findById(Long id) {
return repo.findById(id).get();
}
} }

11
main/src/main/java/gsp/technologies/main/api/position/PositionController.java → main/src/main/java/gsp/technologies/main/api/position/PositionApiController.java

@ -1,5 +1,7 @@
package gsp.technologies.main.api.position; package gsp.technologies.main.api.position;
import java.util.Collection;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -20,12 +22,12 @@ import org.springframework.web.bind.annotation.RestController;
@RestController @RestController
@RequestMapping(path = "/api/v1/positions") @RequestMapping(path = "/api/v1/positions")
public class PositionController { public class PositionApiController {
private static final Logger log = LoggerFactory.getLogger(PositionController.class); private static final Logger log = LoggerFactory.getLogger(PositionApiController.class);
@Autowired @Autowired
private PositionService positionService; private PositionService positionService;
public PositionController(PositionService positionService) { public PositionApiController(PositionService positionService) {
this.positionService = positionService; this.positionService = positionService;
} }
@ -55,7 +57,8 @@ public class PositionController {
// return new ResponseEntity<PagedModel<EntityModel<PositionEntity>>>(assembler.toModel(page), HttpStatus.OK); // return new ResponseEntity<PagedModel<EntityModel<PositionEntity>>>(assembler.toModel(page), HttpStatus.OK);
} }
Page<PositionEntity> page = positionService.findAll(of); Page<PositionEntity> page = positionService.findAll(of);
return new ResponseEntity<>(page, HttpStatus.OK); Collection<PositionEntity> content = page.getContent();
return new ResponseEntity<>(content, HttpStatus.OK);
} }
/** /**

3
main/src/main/java/gsp/technologies/main/api/position/PositionEntity.java

@ -7,7 +7,6 @@ import jakarta.persistence.GenerationType;
import jakarta.persistence.Id; import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn; import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne; import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToOne;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
@ -35,4 +34,6 @@ public class PositionEntity {
@OnDelete(action = OnDeleteAction.CASCADE) @OnDelete(action = OnDeleteAction.CASCADE)
private OrganizationEntity organization; private OrganizationEntity organization;
} }

79
main/src/main/java/gsp/technologies/main/api/position/PositionFaceController.java

@ -0,0 +1,79 @@
package gsp.technologies.main.api.position;
import java.util.Collection;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import gsp.technologies.main.api.organization.OrganizationEntity;
import gsp.technologies.main.api.organization.OrganizationService;
@Controller
@RequestMapping(path = "/positions")
public class PositionFaceController {
private static final Logger log = LoggerFactory.getLogger(PositionFaceController.class);
@Autowired
private OrganizationService organizationService;
@Autowired
private PositionService positionService;
public PositionFaceController(PositionService positionService, OrganizationService organizationService) {
this.positionService = positionService;
this.organizationService = organizationService;
}
/**
* Главная страница работы с должностями
*/
@GetMapping("")
public String positions(Model model) {
log.info("GET /positions");
// получаем список организаций
Collection<OrganizationEntity> organizations = organizationService.findAll()
.stream().sorted((o1, o2) -> o1.getName().compareTo(o2.getName())).collect(Collectors.toList());
//
model.addAttribute("organizations", organizations);
//получаем список должностей
int number = 0;
int size = 100;
String sortBy = "name";
Sort sort = Sort.by(sortBy);
Pageable of = PageRequest.of(number, size, sort);
Collection<PositionEntity> positions = positionService.findAll(of).getContent();
model.addAttribute("positions", positions);
return "positions/main";
}
/**
* Добавление должности
*/
@PostMapping("")
public String create(
@RequestParam(name = "name", required = true) String name,
@RequestParam(name = "organizationId", required = true) Long organizationId) {
log.info("POST /positions");
PositionEntity entity = new PositionEntity();
entity.setName(name);
entity.setOrganization(organizationService.findById(organizationId));
positionService.save(entity);
return "redirect:/positions";
}
}

4
main/src/main/java/gsp/technologies/main/api/position/PositionRepository.java

@ -1,5 +1,7 @@
package gsp.technologies.main.api.position; package gsp.technologies.main.api.position;
import java.util.Collection;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
@ -10,4 +12,6 @@ public interface PositionRepository extends JpaRepository<PositionEntity, Long>
Page<PositionEntity> findByOrganizationId(Pageable of, long organizationId); Page<PositionEntity> findByOrganizationId(Pageable of, long organizationId);
Collection<PositionEntity> findByOrganizationId(Long id);
} }

16
main/src/main/java/gsp/technologies/main/api/position/PositionService.java

@ -1,5 +1,7 @@
package gsp.technologies.main.api.position; package gsp.technologies.main.api.position;
import java.util.Collection;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -16,6 +18,10 @@ public class PositionService {
return repo.findByOrganizationId(of, id); return repo.findByOrganizationId(of, id);
} }
public Collection<PositionEntity> findAllByOrganizationId(Long id) {
return repo.findByOrganizationId(id);
}
public Page<PositionEntity> findAll(Pageable of) { public Page<PositionEntity> findAll(Pageable of) {
return repo.findAll(of); return repo.findAll(of);
} }
@ -23,4 +29,14 @@ public class PositionService {
public void save(PositionEntity position) { public void save(PositionEntity position) {
repo.save(position); repo.save(position);
} }
public Collection<PositionEntity> findAll() {
return repo.findAll();
}
public PositionEntity findById(Long id) {
return repo.findById(id).orElse(null);
}
} }

8
main/src/main/java/gsp/technologies/main/quiz/QuizController.java → main/src/main/java/gsp/technologies/main/api/quiz/QuizController.java

@ -1,4 +1,4 @@
package gsp.technologies.main.quiz; package gsp.technologies.main.api.quiz;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -8,7 +8,6 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import gsp.technologies.main.account.dto.AccountDTO;
@Controller @Controller
@RequestMapping(path = "/quiz") @RequestMapping(path = "/quiz")
@ -18,12 +17,7 @@ public class QuizController {
@GetMapping("") @GetMapping("")
public String quiz(Model model, @RequestParam(name = "accountid", required = true) String accountid) { public String quiz(Model model, @RequestParam(name = "accountid", required = true) String accountid) {
log.info("GET /quiz"); log.info("GET /quiz");
AccountDTO accountDTO = AccountDTO.builder()
.id(accountid)
.code(accountid)
.build();
model.addAttribute("account", accountDTO);
return "quiz"; return "quiz";
} }
} }

46
main/src/main/java/gsp/technologies/main/api/target/TargetEntity.java

@ -0,0 +1,46 @@
package gsp.technologies.main.api.target;
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;
import gsp.technologies.main.api.course.CourseEntity;
import gsp.technologies.main.api.position.PositionEntity;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Entity
public class TargetEntity {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
// На одну должность может быть несколько целей
@ManyToOne(fetch = FetchType.EAGER, optional = false)
@JoinColumn(name = "position", referencedColumnName = "id")
@OnDelete(action = OnDeleteAction.CASCADE)
private PositionEntity position;
// На один курс может быть несколько целей
@ManyToOne(fetch = FetchType.EAGER, optional = false)
@JoinColumn(name = "course", referencedColumnName = "id")
@OnDelete(action = OnDeleteAction.CASCADE)
private CourseEntity course;
private Integer questionsCount;
private Integer questionsLimit;
}

91
main/src/main/java/gsp/technologies/main/api/target/TargetFaceController.java

@ -0,0 +1,91 @@
package gsp.technologies.main.api.target;
import java.util.Collection;
import java.util.Collections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import gsp.technologies.main.api.course.CourseEntity;
import gsp.technologies.main.api.course.CourseService;
import gsp.technologies.main.api.organization.OrganizationEntity;
import gsp.technologies.main.api.organization.OrganizationService;
import gsp.technologies.main.api.position.PositionEntity;
import gsp.technologies.main.api.position.PositionService;
@Controller
@RequestMapping(path = "/targets")
public class TargetFaceController {
private static final Logger log = LoggerFactory.getLogger(TargetFaceController.class);
@Autowired
private TargetService targetService;
@Autowired
private OrganizationService organizationService;
@Autowired
private PositionService positionService;
@Autowired
private CourseService courseService;
public TargetFaceController(TargetService targetService, OrganizationService organizationService, PositionService positionService, CourseService courseService) {
this.targetService = targetService;
this.organizationService = organizationService;
this.positionService = positionService;
this.courseService = courseService;
}
@GetMapping("")
public String targets(Model model) {
log.info("GET /targets");
//передаем в шаблон перечень организаций
Collection <OrganizationEntity> organizations = organizationService.findAll();
model.addAttribute("organizations", organizations);
//передаем в шаблон перечень должностей
Collection <PositionEntity> positions = positionService.findAll();
model.addAttribute("positions", positions);
//передаем в шаблон перечень курсов
Collection <CourseEntity> courses = courseService.findAll();
model.addAttribute("courses", courses);
//передаем в шаблон перечень созданных задачь
Collection <TargetEntity> targets = targetService.findAll();
model.addAttribute("targets", targets);
return "targets/main";
}
@PostMapping("")
public String create(
@RequestParam(name = "courseid", required = true) Long courseid,
@RequestParam(name = "positionid", required = true) Long positionid,
@RequestParam(name = "questions-count", required = true) Integer questionsCount,
@RequestParam(name = "questions-limit", required = true) Integer questionsLimit
){
log.info("POST /targets");
TargetEntity entity = TargetEntity.builder()
.course(courseService.findById(courseid))
.position(positionService.findById(positionid))
.questionsCount(questionsCount)
.questionsLimit(questionsLimit)
.build();
targetService.save(entity);
return "redirect:/targets";
}
}

9
main/src/main/java/gsp/technologies/main/api/target/TargetRepository.java

@ -0,0 +1,9 @@
package gsp.technologies.main.api.target;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface TargetRepository extends JpaRepository<TargetEntity, Long> {
}

34
main/src/main/java/gsp/technologies/main/api/target/TargetService.java

@ -0,0 +1,34 @@
package gsp.technologies.main.api.target;
import java.util.Collection;
import org.springframework.stereotype.Service;
import gsp.technologies.main.api.course.CourseEntity;
import gsp.technologies.main.api.position.PositionEntity;
@Service
public class TargetService {
private final TargetRepository repo;
public TargetService(TargetRepository repo) {
this.repo = repo;
}
public Collection<TargetEntity> findAll() {
return repo.findAll();
}
public TargetEntity save(TargetEntity entity) {
return repo.save(entity);
}
public Collection<CourseEntity> findAllByPosition(PositionEntity position) {
return repo.findAllByPosition(position);
}
public Collection<TargetEntity> findAllByPositionId(Long id) {
return repo.findAllByPositionId(id);
}
}

36
main/src/main/java/gsp/technologies/main/course/CourseController.java

@ -1,36 +0,0 @@
package gsp.technologies.main.course;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import gsp.technologies.main.account.dto.AccountDTO;
import gsp.technologies.main.code.Code;
@Controller
@RequestMapping(path = "/courses")
public class CourseController {
private static final Logger log = LoggerFactory.getLogger(CourseController.class);
@PostMapping("/view")
public String coursewithdata(Model model, @RequestParam(name = "courseid", required = true) String courseid, @RequestParam(name = "accountid", required = true) String accountid) {
log.info("GET /courses/view");
log.info("Account пришедший в контроллер: {}", accountid);
model.addAttribute("courseid", courseid + "");
//получить полный аккаунт из репозитория по id
AccountDTO acc = AccountDTO.builder()
.id(accountid)
.code(Code.encode(accountid))
.build();
model.addAttribute("account", acc);
return "course";
}
}

19
main/src/main/java/gsp/technologies/main/course/dto/CourseDTO.java

@ -1,19 +0,0 @@
package gsp.technologies.main.course.dto;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Data
public class CourseDTO implements Serializable {
private String id;
private String name;
private Boolean passed;
}

37
main/src/main/java/gsp/technologies/main/mainframe/MainframeController.java

@ -1,11 +1,25 @@
package gsp.technologies.main.mainframe; package gsp.technologies.main.mainframe;
import java.util.Collection;
import java.util.stream.Collectors;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.RequestContextHolder;
import gsp.technologies.main.api.organization.OrganizationEntity;
import gsp.technologies.main.api.organization.OrganizationService;
import gsp.technologies.main.api.position.PositionEntity;
import gsp.technologies.main.api.position.PositionService;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
/** /**
@ -18,12 +32,33 @@ import org.springframework.web.bind.annotation.GetMapping;
@Controller @Controller
@RequestMapping(path = "/mainframe") @RequestMapping(path = "/mainframe")
public class MainframeController { public class MainframeController {
@Autowired
private OrganizationService organizationService;
@Autowired
private PositionService positionService;
public MainframeController(PositionService positionService) {
this.positionService = positionService;
}
private static final Logger log = LoggerFactory.getLogger(MainframeController.class); private static final Logger log = LoggerFactory.getLogger(MainframeController.class);
@GetMapping("") @GetMapping("")
public String mainframe() { public String mainframe(Model model) {
log.info("GET /mainframe"); log.info("GET /mainframe");
log.info("текущая сессия: {}", RequestContextHolder.currentRequestAttributes().getSessionId()); log.info("текущая сессия: {}", RequestContextHolder.currentRequestAttributes().getSessionId());
//получаем список организаций
Collection<OrganizationEntity> organizations = organizationService.findAll();
//сортировка организаций
organizations = organizations.stream().sorted((o1, o2) -> o1.getName().compareTo(o2.getName())).collect(Collectors.toList());
//передаем список организаций в шаблон
model.addAttribute("organizations", organizations);
//берем первую в списке организацию
OrganizationEntity organization = organizations.stream().findFirst().get();
//получаем список должностей по организации
Collection<PositionEntity> positions = positionService.findAllByOrganizationId(organization.getId());
model.addAttribute("positions", positions);
//сравнить номер сессии с имеющимися в базе //сравнить номер сессии с имеющимися в базе
//при наличии вернуть порядковый номер существующей сессии (в 35-ричной системе счисления) //при наличии вернуть порядковый номер существующей сессии (в 35-ричной системе счисления)

2
main/src/main/resources/templates/account.html

@ -21,7 +21,7 @@ xmlns:th="http://www.thymeleaf.org">
</header> </header>
<body> <body>
<!-- Перечень доступных курсов --> <!-- Перечень доступных курсов -->
<div th:insert="~{fragments/account :: courses(account=${account})}"></div> <!-- <div th:insert="~{fragments/account :: courses(account=${account})}"></div> -->
</body> </body>
<footer> <footer>
<!-- Выход из аккаунта, обновление сессии --> <!-- Выход из аккаунта, обновление сессии -->

6
main/src/main/resources/templates/course.html

@ -4,7 +4,7 @@ xmlns:th="http://www.thymeleaf.org">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>exam-account</title> <title>exam-course</title>
<script src="https://cdn.jsdelivr.net/npm/@webcomponents/webcomponentsjs@2/webcomponents-loader.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/@webcomponents/webcomponentsjs@2/webcomponents-loader.min.js"></script>
<script type="module" src="https://cdn.jsdelivr.net/gh/zerodevx/zero-md@1/src/zero-md.min.js"></script> <script type="module" src="https://cdn.jsdelivr.net/gh/zerodevx/zero-md@1/src/zero-md.min.js"></script>
<style> <style>
@ -17,12 +17,12 @@ xmlns:th="http://www.thymeleaf.org">
</head> </head>
<header> <header>
<!-- Информация об аккаунте: id, organization, position --> <!-- Информация об аккаунте: id, organization, position -->
<div th:insert="~{fragments/account :: info(account=${account})}"></div> <!-- <div th:insert="~{fragments/account :: info(account=${account})}"></div> -->
</header> </header>
<body> <body>
<!-- курс --> <!-- курс -->
<div th:insert="~{fragments/course :: main(id=${courseid})}"></div> <div th:insert="~{fragments/course :: main(id=${courseid})}"></div>
<div th:insert="~{fragments/controls :: gotoQuiz(accountid=${account.id})}"></div> <!-- <div th:insert="~{fragments/controls :: gotoQuiz(accountid=${account.id})}"></div> -->
</body> </body>
<footer> <footer>
<!-- Выход из аккаунта, обновление сессии --> <!-- Выход из аккаунта, обновление сессии -->

58
main/src/main/resources/templates/courses/fragments/main.html

@ -0,0 +1,58 @@
<!-- Коллекция фрагментов для построения страницы организаций -->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<!-- Перечень курсов -->
<div th:fragment="list(courses)">
<hr>
<h2>Список курсов:</h2>
<table>
<thead>
<tr>
<th>ID</th>
<th>Наименование</th>
<th>Действия</th>
</tr>
</thead>
<tbody>
<tr th:each="course : ${courses}">
<td th:text="${course.id}"></td>
<td th:text="${course.name}"></td>
<td>
<a th:href="@{/courses/{id}/edit(id=${course.id})}">Редактировать</a>
<a th:href="@{/courses/{id}/delete(id=${course.id})}">Удалить</a>
</td>
</tr>
</tbody>
</table>
<hr>
<!-- <div th:each="course : ${courses}">
<div th:text="${course.name}"></div>
</div> -->
</div>
<!-- Добавление нового курса -->
<div th:fragment="create">
<hr>
<h2>Добавление нового курса:</h2>
<form th:action="@{/courses}" th:method="post">
<label for="name">Наименование курса </label>
<input type="text" id="name" name="name">
<input type="submit" value="Добавить">
</form>
</div>
<!-- Редактирование курсов -->
<!-- <div th:fragment="edit(position)">
<hr>
<h2>Редактирование должности: <span th:text="${position.name}"></span></h2>
<form th:action="@{/positions/{id}/edit(id=${position.id})}" th:method="post">
<label for="name" >Наименование должности: </label>
<input type="text" th:name="name" th:value="${position.name}">
<br>
<input type="submit" value="Сохранить">
</form>
</div> -->
</body>
</html>

25
main/src/main/resources/templates/courses/main.html

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>exam-courses</title>
<script src="https://cdn.jsdelivr.net/npm/@webcomponents/webcomponentsjs@2/webcomponents-loader.min.js"></script>
<script type="module" src="https://cdn.jsdelivr.net/gh/zerodevx/zero-md@1/src/zero-md.min.js"></script>
</head>
<header>
</header>
<body>
<h1>Фрагменты для работы с курсами</h1>
<!-- Добавление нового курса -->
<div th:insert="~{courses/fragments/main :: create}"></div>
<!-- Перечень курсов -->
<div th:insert="~{courses/fragments/main :: list(courses=${courses})}"></div>
</body>
<footer>
<div th:insert="~{fragments/common/footer :: copy}"></div>
</footer>
</html>

26
main/src/main/resources/templates/error.html

@ -0,0 +1,26 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>exam-error</title>
<script src="https://cdn.jsdelivr.net/npm/@webcomponents/webcomponentsjs@2/webcomponents-loader.min.js"></script>
<script type="module" src="https://cdn.jsdelivr.net/gh/zerodevx/zero-md@1/src/zero-md.min.js"></script>
</head>
<header>
</header>
<body>
<div>
<h1>Выявлена ошибка:</h1>
<p th:text="${error}"></p>
</div>
<form th:action="@{/mainframe}" method="get">
<input type="submit" value="ПЕРЕЙТИ НА ГЛАВНУЮ СТРАНИЦУ">
</form>
</body>
<footer>
<div th:insert="~{fragments/common/footer :: copy}"></div>
</footer>
</html>

7
main/src/main/resources/templates/fragments/account.html

@ -8,18 +8,19 @@
<!-- <span>id: <span th:text="${account.id}"></span></span> <!-- <span>id: <span th:text="${account.id}"></span></span>
<br> --> <br> -->
<span class="code">ID: <span th:text="${account.code}"></span></span> <span class="code">ID: <span th:text="${account.code}"></span></span>
<!-- <br> <!-- <br> -->
<span>session: <span th:text="${account.sessionid}"></span></span> <!-- <span>session: <span th:text="${account.sessionid}"></span></span> -->
<br> <br>
<span>organization: <span th:text="${account.position.organization.name}"></span></span> <span>organization: <span th:text="${account.position.organization.name}"></span></span>
<br> <br>
<span>position: <span th:text="${account.position.name}"></span></span> --> <span>position: <span th:text="${account.position.name}"></span></span>
</div> </div>
<!-- Доступные на аккаунте курсы --> <!-- Доступные на аккаунте курсы -->
<div th:fragment="courses(account)"> <div th:fragment="courses(account)">
<hr> <hr>
<h2>Доступные курсы:</h1>
<table> <table>
<thead> <thead>
<th>номер</th> <th>номер</th>

39
main/src/main/resources/templates/fragments/controls.html

@ -3,30 +3,26 @@
<html xmlns:th="http://www.thymeleaf.org"> <html xmlns:th="http://www.thymeleaf.org">
<body> <body>
<!-- регистрация --> <!-- регистрация -->
<div th:fragment="exam"> <div th:fragment="exam(organizations)">
<hr> <hr>
<p>Укажите данные для создания нового задания</p> <p>Укажите данные для создания нового задания</p>
<!-- отправляем наименование компании и наименование должности
для перехода на целевой курс -->
<form th:action="@{/account}" th:method="get">
<label for="company">компания: </label>
<select>
<option value="1">ГСП-1</option>
<option value="2">ГСП-2</option>
<option value="3">ГСП-3</option>
<option value="4">ГСП-4</option>
</select>
<br>
<label for="profession">должность: </label> <!-- Выбираем наименование компании,
<select> для формирвоания соответствующего списка должностей -->
<option value="1">сварщик</option> <label for="organization-select">Выберите компанию</label>
<option value="2">монтажник</option> <select id="organization-select" name="organizationid">
<option value="3">специалист ПТО</option> <option value="0" disabled selected>компания</option>
<option value="4">дефектоскопист</option> <option th:each="organization : ${organizations}" th:value="${organization.id}" th:text="${organization.name}"></option>
</select> </select>
<br>
<!-- отправляем наименование наименование должности
для перехода на целевой курс -->
<form th:action="@{/account}" th:method="get">
<label for="position-select">Выберите должность</label>
<select id="position-select" name="positionid">
<option value="0" disabled selected>должность</option>
<option th:each="position : ${positions}" th:value="${position.id}" th:text="${position.name}"></option>
</select>
<input type="submit" value="Создать аккаунт"> <input type="submit" value="Создать аккаунт">
</form> </form>
</div> </div>
@ -35,9 +31,9 @@
<div th:fragment="auth"> <div th:fragment="auth">
<!-- Отправляем запрос с параметром code <!-- Отправляем запрос с параметром code
открываем существующую попытку --> открываем существующую попытку -->
<form th:action="@{/auth}" th:method="post"> <form th:action="@{/account}" th:method="get">
<label for="code">Если Вам нужно продолжить прохождение уже начатого курса - введите ID своего аккаунта: </label> <label for="code">Если Вам нужно продолжить прохождение уже начатого курса - введите ID своего аккаунта: </label>
<input type="text" id="code" name="code"> <input type="text" id="code" name="accountid">
<input type="submit" value="Проверить код"> <input type="submit" value="Проверить код">
</form> </form>
</div> </div>
@ -59,4 +55,5 @@
</form> </form>
</div> </div>
</body> </body>
</html> </html>

34
main/src/main/resources/templates/mainframe.html

@ -16,10 +16,42 @@ xmlns:th="http://www.thymeleaf.org">
<!-- пояснения, приветствие --> <!-- пояснения, приветствие -->
<div th:insert="~{fragments/hello :: main}"></div> <div th:insert="~{fragments/hello :: main}"></div>
<!-- создаем новую попытку --> <!-- создаем новую попытку -->
<div th:insert="~{fragments/controls :: exam}"></div> <div th:insert="~{fragments/controls :: exam(organizations=${organizations})}"></div>
</body> </body>
<footer> <footer>
<div th:insert="~{fragments/controls :: logout}"></div> <div th:insert="~{fragments/controls :: logout}"></div>
<div th:insert="~{fragments/common/footer :: copy}"></div> <div th:insert="~{fragments/common/footer :: copy}"></div>
</footer> </footer>
<script>
// Функция для загрузки должностей
function loadPositions() {
let organizationSelect = document.getElementById('organization-select');
let organizationId = organizationSelect.value;
let req = new XMLHttpRequest();
req.open("GET", "http://localhost:100/api/v1/positions?id=" + organizationId, false);
req.send(null);
let positions = JSON.parse(req.responseText);
console.log(positions);
let positionSelect = document.getElementById('position-select');
positionSelect.innerHTML = '';
// поле "должность" в селекте
let option = document.createElement('option');
option.value = 0;
option.text = "должность";
option.disabled = true;
option.selected = true;
positionSelect.add(option);
// Добавление остальных должностей
for (let i = 0; i < positions.content.length; i++) {
let option = document.createElement('option');
option.value = positions.content[i].id;
option.text = positions.content[i].name;
positionSelect.add(option);
}
}
// Загрузка должностей при выборе организации
let organizationSelect = document.getElementById('organization-select');
organizationSelect.addEventListener('change', loadPositions);
</script>
</html> </html>

23
main/src/main/resources/templates/organizations/edit.html

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>exam-organizations-edit</title>
<script src="https://cdn.jsdelivr.net/npm/@webcomponents/webcomponentsjs@2/webcomponents-loader.min.js"></script>
<script type="module" src="https://cdn.jsdelivr.net/gh/zerodevx/zero-md@1/src/zero-md.min.js"></script>
</head>
<header>
</header>
<body>
<h1>Фрагменты для работы с данными организаций</h1>
<!-- Редактирование организации -->
<div th:insert="~{organizations/fragments/main :: edit(organization=${organization})}"></div>
</body>
<footer>
<div th:insert="~{fragments/common/footer :: copy}"></div>
</footer>
</html>

57
main/src/main/resources/templates/organizations/fragments/main.html

@ -0,0 +1,57 @@
<!-- Коллекция фрагментов для построения страницы организаций -->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<!-- Перечень организаций -->
<div th:fragment="list(organizations)">
<hr>
<h2>Список организаций:</h2>
<table>
<thead>
<tr>
<th>Название организации</th>
<th>Действия</th>
</tr>
</thead>
<tbody>
<tr th:each="organization : ${organizations}">
<td th:text="${organization.name}"></td>
<td>
<a th:href="@{/organizations/{id}/edit(id=${organization.id})}">Редактировать</a>
<a th:href="@{/organizations/{id}/delete(id=${organization.id})}">Удалить</a>
</td>
</tr>
</tbody>
</table>
<hr>
<div th:each="organization : ${organizations}">
<div th:text="${organization.name}"></div>
</div>
</div>
<!-- Добавление новой организации -->
<div th:fragment="create">
<hr>
<h2>Добавление новой организации:</h2>
<form th:action="@{/organizations}" th:method="post">
<label for="name">Название организации: </label>
<input type="text" id="name" name="name">
<br>
<input type="submit" value="Добавить">
</form>
</div>
<!-- Редактирование организации -->
<div th:fragment="edit(organization)">
<hr>
<h2>Редактирование организации: <span th:text="${organization.name}"></span></h2>
<form th:action="@{/organizations/{id}/edit(id=${organization.id})}" th:method="post">
<label for="name" >Название организации: </label>
<input type="text" th:name="name" th:value="${organization.name}">
<br>
<input type="submit" value="Сохранить">
</form>
</div>
</body>
</html>

10
main/src/main/resources/templates/organizations/main.html

@ -4,15 +4,21 @@ xmlns:th="http://www.thymeleaf.org">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>exam-main-hello</title> <title>exam-organizations</title>
<script src="https://cdn.jsdelivr.net/npm/@webcomponents/webcomponentsjs@2/webcomponents-loader.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/@webcomponents/webcomponentsjs@2/webcomponents-loader.min.js"></script>
<script type="module" src="https://cdn.jsdelivr.net/gh/zerodevx/zero-md@1/src/zero-md.min.js"></script> <script type="module" src="https://cdn.jsdelivr.net/gh/zerodevx/zero-md@1/src/zero-md.min.js"></script>
</head> </head>
<header> <header>
</header> </header>
<body> <body>
<h1>organizations</h1> <h1>Фрагменты для работы с данными организаций</h1>
<!-- Давление новой организации -->
<div th:insert="~{organizations/fragments/main :: create}"></div>
<!-- Перечень организаций -->
<div th:insert="~{organizations/fragments/main :: list(organizations=${organizations})}"></div>
</body> </body>
<footer> <footer>
<div th:insert="~{fragments/common/footer :: copy}"></div> <div th:insert="~{fragments/common/footer :: copy}"></div>
</footer> </footer>

64
main/src/main/resources/templates/positions/fragments/main.html

@ -0,0 +1,64 @@
<!-- Коллекция фрагментов для построения страницы организаций -->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<!-- Перечень организаций -->
<div th:fragment="list(positions)">
<hr>
<h2>Список должностей:</h2>
<table>
<thead>
<tr>
<th>Организация</th>
<th>Должность</th>
<th>Действия</th>
</tr>
</thead>
<tbody>
<tr th:each="position : ${positions}">
<td th:text="${position.organization.name}"></td>
<td th:text="${position.name}"></td>
<td>
<a th:href="@{/positions/{id}/edit(id=${position.id})}">Редактировать</a>
<a th:href="@{/positions/{id}/delete(id=${position.id})}">Удалить</a>
</td>
</tr>
</tbody>
</table>
<hr>
<div th:each="position : ${positions}">
<div th:text="${position.name}"></div>
</div>
</div>
<!-- Добавление новой должности -->
<div th:fragment="create(organizations)">
<hr>
<h2>Добавление новой должности:</h2>
<form th:action="@{/positions}" th:method="post">
<label for="organizationId">Организация: </label>
<select id="organizationId" name="organizationId">
<option value="0" disabled >выберите организацию</option>
<option th:each="organization : ${organizations}" th:value="${organization.id}" th:text="${organization.name}"></option>
</select>
<label for="name">Наименование должности: </label>
<input type="text" id="name" name="name">
<br>
<input type="submit" value="Добавить">
</form>
</div>
<!-- Редактирование олжностей -->
<!-- <div th:fragment="edit(position)">
<hr>
<h2>Редактирование должности: <span th:text="${position.name}"></span></h2>
<form th:action="@{/positions/{id}/edit(id=${position.id})}" th:method="post">
<label for="name" >Наименование должности: </label>
<input type="text" th:name="name" th:value="${position.name}">
<br>
<input type="submit" value="Сохранить">
</form>
</div> -->
</body>
</html>

25
main/src/main/resources/templates/positions/main.html

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>exam-positions</title>
<script src="https://cdn.jsdelivr.net/npm/@webcomponents/webcomponentsjs@2/webcomponents-loader.min.js"></script>
<script type="module" src="https://cdn.jsdelivr.net/gh/zerodevx/zero-md@1/src/zero-md.min.js"></script>
</head>
<header>
</header>
<body>
<h1>Фрагменты для работы с данными о должностях</h1>
<!-- Добавление новой должности -->
<div th:insert="~{positions/fragments/main :: create(organizations=${organizations})}"></div>
<!-- Перечень должностей -->
<div th:insert="~{positions/fragments/main :: list(positions=${positions})}"></div>
</body>
<footer>
<div th:insert="~{fragments/common/footer :: copy}"></div>
</footer>
</html>

104
main/src/main/resources/templates/targets/fragments/main.html

@ -0,0 +1,104 @@
<!-- Коллекция фрагментов для построения страницы организаций -->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<!-- Перечень задачь -->
<div th:fragment="list(targets)">
<hr>
<h2>Список задачь:</h2>
<table>
<thead>
<tr>
<th>Организация</th>
<th>Должность</th>
<th>Курс</th>
<th>count</th>
<th>limit</th>
<th>Действия</th>
</tr>
</thead>
<tbody>
<tr th:each="target : ${targets}">
<td th:text="${target.position.organization.name}"></td>
<td th:text="${target.position.name}"></td>
<td th:text="${target.course.name}"></td>
<td th:text="${target.questionsCount}"></td>
<td th:text="${target.questionsLimit}"></td>
<td>
<a th:href="@{/targets/{id}/edit(id=${target.id})}">Редактировать</a>
<a th:href="@{/targets/{id}/delete(id=${target.id})}">Удалить</a>
</td>
</tr>
</tbody>
</table>
</div>
<!-- Добавление новой задачи -->
<!--
- выбор организации
- выбор должности (в организации)
- выбор курса
- указане количества вопросов
- указание лимита вопросов для положительного результата
-->
<div th:fragment="create(organizations, positions, courses)">
<hr>
<h2>Добавление новой задачи:</h2>
<form th:action="@{/targets}" th:method="post">
<!-- выбираем организацию -->
<label for="organization-select">Организация: </label>
<select id="organization-select" name="organizationid">
<option value="0" disabled selected>выберите организацию</option>
<option th:each="organization : ${organizations}" th:value="${organization.id}" th:text="${organization.name}"></option>
</select>
<br>
<!-- отрабатывает скрипт по добавлению селекта должности -->
<!-- выбираем должность -->
<label for="position-select">Должность: </label>
<select id="position-select" name="positionid">
<option value="0" disabled selected>выберите должность</option>
<option th:each="position : ${positions}" th:value="${position.id}" th:text="${position.name}"></option>
</select>
<br>
<label for="course-select">Курс: </label>
<select id="course-select" name="courseid">
<option value="0" disabled selected >выберите курс</option>
<option th:each="course : ${courses}" th:value="${course.id}" th:text="${course.name}"></option>
</select>
<br>
<label for="questions-count">Количество вопросов для проверки знаний: </label>
<br>
<input type="text" id="questions-count" name="questions-count">
<br>
<br>
<label for="questions-limit">Количество вопросов для положительной оценки: </label>
<br>
<input type="text" id="questions-limit" name="questions-limit">
<br>
<input type="submit" value="Добавить">
</form>
</div>
<!-- Редактирование олжностей -->
<!-- <div th:fragment="edit(position)">
<hr>
<h2>Редактирование должности: <span th:text="${position.name}"></span></h2>
<form th:action="@{/positions/{id}/edit(id=${position.id})}" th:method="post">
<label for="name" >Наименование должности: </label>
<input type="text" th:name="name" th:value="${position.name}">
<br>
<input type="submit" value="Сохранить">
</form>
</div> -->
</body>
</html>

56
main/src/main/resources/templates/targets/main.html

@ -0,0 +1,56 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>exam-targets</title>
<script src="https://cdn.jsdelivr.net/npm/@webcomponents/webcomponentsjs@2/webcomponents-loader.min.js"></script>
<script type="module" src="https://cdn.jsdelivr.net/gh/zerodevx/zero-md@1/src/zero-md.min.js"></script>
</head>
<header>
</header>
<body>
<h1>Фрагменты для работы с назначением курсов</h1>
<!-- Добавление новой задачи -->
<div th:insert="~{targets/fragments/main :: create(organizations=${organizations}, positions=${positions}, courses=${courses})}"></div>
<!-- Перечень задачь -->
<div th:insert="~{targets/fragments/main :: list(targets=${targets})}"></div>
</body>
<footer>
<div th:insert="~{fragments/common/footer :: copy}"></div>
</footer>
<script>
// Функция для загрузки должностей
function loadPositions() {
let organizationSelect = document.getElementById('organization-select');
let organizationId = organizationSelect.value;
let req = new XMLHttpRequest();
req.open("GET", "http://localhost:100/api/v1/positions?id=" + organizationId, false);
req.send(null);
let positions = JSON.parse(req.responseText);
console.log(positions);
let positionSelect = document.getElementById('position-select');
positionSelect.innerHTML = '';
// поле "должность" в селекте
let option = document.createElement('option');
option.value = 0;
option.text = "должность";
option.disabled = true;
option.selected = true;
positionSelect.add(option);
// Добавление остальных должностей
for (let i = 0; i < positions.content.length; i++) {
let option = document.createElement('option');
option.value = positions.content[i].id;
option.text = positions.content[i].name;
positionSelect.add(option);
}
}
// Загрузка должностей при выборе организации
let organizationSelect = document.getElementById('organization-select');
organizationSelect.addEventListener('change', loadPositions);
</script>
</html>
Loading…
Cancel
Save