Browse Source

docs

master
esoe 2 weeks ago
parent
commit
8bb5fdea82
  1. 1
      docs/.~lock.base.xlsx#
  2. BIN
      docs/base.xlsx
  3. 157
      docs/erd/main.puml
  4. 3
      main/src/main/java/gsp/technologies/main/access/login/AuthController.java
  5. 22
      main/src/main/java/gsp/technologies/main/account/AccountController.java
  6. 5
      main/src/main/java/gsp/technologies/main/account/dto/AccountDTO.java
  7. 8
      main/src/main/java/gsp/technologies/main/account/dto/OrganizationDTO.java
  8. 4
      main/src/main/java/gsp/technologies/main/account/dto/PositionDTO.java
  9. 6
      main/src/main/java/gsp/technologies/main/code/Code.java
  10. 24
      main/src/main/java/gsp/technologies/main/course/CourseController.java
  11. 4
      main/src/main/java/gsp/technologies/main/course/dto/CourseDTO.java
  12. 29
      main/src/main/java/gsp/technologies/main/quiz/QuizController.java
  13. 16372
      main/src/main/resources/static/content/courses/1/docs/horstman_k_sovremennii_javascript_dlya_neterpelivih_2021.pdf
  14. BIN
      main/src/main/resources/static/content/courses/1/download/7.xlsx
  15. 19
      main/src/main/resources/static/content/courses/1/main.md
  16. BIN
      main/src/main/resources/static/content/courses/1/pictures/main.png
  17. BIN
      main/src/main/resources/static/content/courses/1/video/001.mp4
  18. 1
      main/src/main/resources/static/content/courses/2/main.md
  19. 1
      main/src/main/resources/static/content/courses/3/main.md
  20. 7
      main/src/main/resources/templates/course.html
  21. 12
      main/src/main/resources/templates/fragments/account.html
  22. 41
      main/src/main/resources/templates/fragments/controls.html
  23. 5
      main/src/main/resources/templates/fragments/course.html
  24. 11
      main/src/main/resources/templates/fragments/quiz.html
  25. 29
      main/src/main/resources/templates/quiz.html
  26. BIN
      out/docs/erd/main/main.png

1
docs/.~lock.base.xlsx#

@ -0,0 +1 @@ @@ -0,0 +1 @@
,devpc/devuser,devpc,07.11.2024 10:34,file:///C:/Users/devuser/AppData/Roaming/LibreOffice/4;

BIN
docs/base.xlsx

Binary file not shown.

157
docs/erd/main.puml

@ -0,0 +1,157 @@ @@ -0,0 +1,157 @@
@startuml
!define primary_key(x) <b><color:#b8861b><&key></color> x</b>
!define foreign_key(x) <b><color:#aaaaaa><&key></color> x</b>
!define column(x) <b><color:#efefef><&media-record></color> x</b>
!define table(x) entity x << (T, white) >>
' left to right direction
title "Entity Relationship Diagram (ERD): exam (пополнение и провера знаний)"
' Аккаунты пользователей
table(account) #eaa {
primary_key(id): LONGSERIAL >>"Идентификатор"
column(code): String >>"35-ичный код (логин)"
foreign_key(orgstructure_id): LONGSERIAL >>"идентификатор места работы"
}
' Оргструктура
table(orgstructure) #eaa {
primary_key(id): LONGSERIAL >>"Идентификатор"
foreign_key(organization_id): LONGSERIAL>>"Идентификатор организации"
foreign_key(position_id): LONGSERIAL>>"Идентификатор должности"
}
orgstructure --{ account
' Организации
table(organization) #eaa {
primary_key(id): LONGSERIAL >>"Идентификатор"
column(name): STRING >>"Наименование"
}
organization --{ orgstructure
' Должности
table(position) #eaa {
primary_key(id): LONGSERIAL >>"Идентификатор"
column(name): STRING >>"Наименование"
}
position --{ orgstructure
' Курсы
' По идентификатору курса определяется положение соответствующего курса
' в файловой системе сервиса
table(course){
primary_key(id): LONGSERIAL >>"Идентификатор"
column(name): STRING >>"Наименование"
column(short): STRING >>"Сокращенно"
}
note top
Не понятно, стоит ли хранить в базе пути до контента курса,
или достаточно создавать курсы в виде статических директорий
Если курс состоит из тем, где будет определен порядок представления тем пользователю
end note
' тема
table(theme){
primary_key(id): LONGSERIAL >>"Идентификатор"
column(name): STRING >>"Наименование"
' foreign_key(course_id):LONGSERIAL >>"ID курса"
}
note top
Курс может состоять из одной или нескольких тем
тема определяет состав вопросов, которые смогут попасть в опрос по курсу
Само тело курса также возможно разбить на отдельные темы,
материал по которым будет оформляться в отдельных *.md файлах
end note
' course --{ theme
' порядок расположения тем в курсе
table(scheme){
primary_key(id): LONGSERIAL >>"Идентификатор"
foreign_key(course_id): LONGSERIAL >>"Идентификатор курса"
foreign_key(theme_id): LONGSERIAL >>"Идентификатор темы"
column(position) INTEGER >>"Порядковый номер темы в курсе"
}
note top
Схема курса
определяет последовательность размещения тем в курсе
end note
course --{ scheme
theme --{ scheme
' Список задач
table(target) #eaa {
primary_key(id): LONGSERIAL >>"Идентификатор задачи"
foreign_key(orgstructure_id): LONGSERIAL >>"Идентификатор категории должности"
foreign_key(course_id): LONGSERIAL >>"Идентификатор курса"
column(questions_count): INTEGER >>"Количество вопросов для тестирования"
column(limit): INTEGER >>"Количество вопросов, для успешного завершения опроса"
}
note top
Тут формируется перечень назначенных пользователю курсов,
на основании наименования организации и должности работника
Тут определено общее количество вопросов для тестирвоания,
далее вопросы берутся случайным образом из тем, относящихся к курсу в равных пропорциях
end note
orgstructure --{ target
course --{ target
' Вопросы
table(question){
primary_key(id): LONGSERIAL >>"Идентификатор вопроса"
column(body): String >>"Содержание вопроса"
foreign_key(theme_id): LONGSERIAL >>"Идентификатор темы вопроса"
}
theme --{ question
table(answer){
primary_key(id): LONGSERIAL >>"Идентификатор ответа"
column(body): STRING >>"Содержание ответа"
foreign_key(question_id): LONGSERIAL >>"Идентификатор вопроса"
column(status): BOOLEAN >>"статус ответа: верно / не верно"
column(description): STRING >>"Пояснения, обоснование ответа"
}
question --{ answer
' Опрос
table(quiz) #88f {
primary_key(id): LONGSERIAL >>"Идентификатор опроса"
foreign_key(account_id): LONGSERIAL >>"Идентификатор аккаунта"
foreign_key(target_id): LONGSERIAL >>"Идентификатор задания"
foreign_key(question_id): LONGSERIAL >>"Назначенный вопрос"
foreign_key(answer_id): LONGSERIAL >>"Идентификатор данного ответа"
column(datetime): DATETIME >>"Дата и время ответа"
}
question --{ quiz
target --{ quiz
account --{ quiz
answer --{ quiz
' Результаты
table(results) #88f {
primary_key(id): LONGSERIAL >>"Идентификатор опроса"
foreign_key(account_id): LONGSERIAL >>"Идентификатор аккаунта"
foreign_key(target_id): LONGSERIAL >>"Идентификатор задания"
column(status): BOOLEAN >>"сдано / не сдано"
column(passed): DATETIME >>"Дата завершения"
}
note top
Запись в таблицу результатов происходит
по клику кнопки в графическом интерфейсе
пишется время клика и пересчитываются правильные отвты
end note
quiz --{ results
account -down-{ results
@enduml

3
main/src/main/java/gsp/technologies/main/access/login/AuthController.java

@ -4,11 +4,8 @@ import org.slf4j.Logger; @@ -4,11 +4,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.context.request.RequestContextHolder;
import gsp.technologies.main.mainframe.MainframeController;

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

@ -10,6 +10,10 @@ import org.springframework.web.bind.annotation.GetMapping; @@ -10,6 +10,10 @@ 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;
/**
@ -25,31 +29,31 @@ public class AccountController { @@ -25,31 +29,31 @@ public class AccountController {
public String account(Model model) {
log.info("GET /account");
//данные аккаунта (id, organization, position)
Long id = 1L;
String id = 1 + "";
String code = Code.encode(id);
OrganizationDTO organization = OrganizationDTO.builder()
.id(1L)
.id(1 + "")
.name("ГСП-Т")
.build();
PositionDTO position = PositionDTO.builder()
.id(1L)
.id(1 + "")
.name("Сварщик")
.organization(organization)
.build();
String sessionid = RequestContextHolder.currentRequestAttributes().getSessionId();
List<CourseDTO> courses = List.of(
CourseDTO.builder()
.id(1L)
.id(1 + "")
.name("Охрана труда")
.passed(true)
.build(),
CourseDTO.builder()
.id(2L)
.id(2 + "")
.name("Работы на высоте")
.passed(false)
.build(),
CourseDTO.builder()
.id(3L)
.id(3 + "")
.name("Первая помощь")
.passed(true)
.build()
@ -62,11 +66,9 @@ public class AccountController { @@ -62,11 +66,9 @@ public class AccountController {
.courses(courses)
.build();
// log.info("account: {}", account);
model.addAttribute("account", account);
log.info("account: " + account);
//перечень назначенных курсов
// ...
log.info("Акаунт добавлен в модель: {}", account);
return "account";
}

5
main/src/main/java/gsp/technologies/main/account/AccountDTO.java → main/src/main/java/gsp/technologies/main/account/dto/AccountDTO.java

@ -1,8 +1,9 @@ @@ -1,8 +1,9 @@
package gsp.technologies.main.account;
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;
@ -13,7 +14,7 @@ import lombok.NoArgsConstructor; @@ -13,7 +14,7 @@ import lombok.NoArgsConstructor;
@AllArgsConstructor
@Data
public class AccountDTO implements Serializable {
private Long id;
private String id;
private String code;
private PositionDTO position;
private String sessionid;

8
main/src/main/java/gsp/technologies/main/account/OrganizationDTO.java → main/src/main/java/gsp/technologies/main/account/dto/OrganizationDTO.java

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

4
main/src/main/java/gsp/technologies/main/account/PositionDTO.java → main/src/main/java/gsp/technologies/main/account/dto/PositionDTO.java

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

6
main/src/main/java/gsp/technologies/main/code/Code.java

@ -9,9 +9,15 @@ public abstract class Code { @@ -9,9 +9,15 @@ public abstract class Code {
return code;
}
public static String encode(String value) {
String code = value;
return code;
}
public static Long decode(String code) {
Long value = Long.valueOf(code);
return value;
}
}

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

@ -3,20 +3,34 @@ package gsp.technologies.main.course; @@ -3,20 +3,34 @@ package gsp.technologies.main.course;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
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);
@GetMapping("/view/{id}")
public String course(@PathVariable Long id) {
log.info("GET /courses");
@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";
}
}

4
main/src/main/java/gsp/technologies/main/account/CourseDTO.java → main/src/main/java/gsp/technologies/main/course/dto/CourseDTO.java

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
package gsp.technologies.main.account;
package gsp.technologies.main.course.dto;
import java.io.Serializable;
@ -13,7 +13,7 @@ import lombok.NoArgsConstructor; @@ -13,7 +13,7 @@ import lombok.NoArgsConstructor;
@Data
public class CourseDTO implements Serializable {
private Long id;
private String id;
private String name;
private Boolean passed;
}

29
main/src/main/java/gsp/technologies/main/quiz/QuizController.java

@ -0,0 +1,29 @@ @@ -0,0 +1,29 @@
package gsp.technologies.main.quiz;
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.bind.annotation.RequestParam;
import gsp.technologies.main.account.dto.AccountDTO;
@Controller
@RequestMapping(path = "/quiz")
public class QuizController {
private static final Logger log = LoggerFactory.getLogger(QuizController.class);
@GetMapping("")
public String quiz(Model model, @RequestParam(name = "accountid", required = true) String accountid) {
log.info("GET /quiz");
AccountDTO accountDTO = AccountDTO.builder()
.id(accountid)
.code(accountid)
.build();
model.addAttribute("account", accountDTO);
return "quiz";
}
}

16372
main/src/main/resources/static/content/courses/1/docs/horstman_k_sovremennii_javascript_dlya_neterpelivih_2021.pdf

File diff suppressed because one or more lines are too long

BIN
main/src/main/resources/static/content/courses/1/download/7.xlsx

Binary file not shown.

19
main/src/main/resources/static/content/courses/1/main.md

@ -1,2 +1,17 @@ @@ -1,2 +1,17 @@
# Первая помощь
![pic](/content/courses/1/pictures/states.png)
# Курс: Охрана труда
## Структура фреймов интерфейса
![структура фреймов интерфейса](/content/courses/1/pictures/states.png)
## Структура базы данных
![структура базы данных](/content/courses/1/pictures/main.png)
## Посмотрите поучительное видео про медоедов!
<!-- <video src='/content/courses/1/video/Медоеду похер.mp4' width=180/> -->
<video controls src="/content/courses/1/video/001.mp4" title="Title"></video>
## Документы на скачивание
[скачать](/content/courses/1/download/7.xlsx)
## документ на просмотр в новой вкладке
<a href="/content/courses/1/docs/horstman_k_sovremennii_javascript_dlya_neterpelivih_2021.pdf" target="_blank">javascript_dlya_neterpelivih_2021 в новой вкладке</a>

BIN
main/src/main/resources/static/content/courses/1/pictures/main.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 KiB

BIN
main/src/main/resources/static/content/courses/1/video/001.mp4

Binary file not shown.

1
main/src/main/resources/static/content/courses/2/main.md

@ -0,0 +1 @@ @@ -0,0 +1 @@
# Курс: Работы на высоте

1
main/src/main/resources/static/content/courses/3/main.md

@ -0,0 +1 @@ @@ -0,0 +1 @@
# Курс: Первая помощь

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

@ -17,11 +17,12 @@ xmlns:th="http://www.thymeleaf.org"> @@ -17,11 +17,12 @@ xmlns:th="http://www.thymeleaf.org">
</head>
<header>
<!-- Информация об аккаунте: id, organization, position -->
<!-- <div th:insert="~{fragments/account :: info(account=${account})}"></div> -->
<div th:insert="~{fragments/account :: info(account=${account})}"></div>
</header>
<body>
<!-- первый курс -->
<div th:insert="~{fragments/course :: main}"></div>
<!-- курс -->
<div th:insert="~{fragments/course :: main(id=${courseid})}"></div>
<div th:insert="~{fragments/controls :: gotoQuiz(accountid=${account.id})}"></div>
</body>
<footer>
<!-- Выход из аккаунта, обновление сессии -->

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

@ -25,19 +25,25 @@ @@ -25,19 +25,25 @@
<th>номер</th>
<th>наименование</th>
<th>статус</th>
<th>просмотреть</th>
</thead>
<tbody>
<tr th:each="course : ${account.courses}">
<td th:text="${course.id}"></td>
<td>
<a th:href="@{/courses/view/{id}(id=${course.id})}" th:text="${course.name}"></a>
</td>
<td th:text="${course.name}"></td>
<td>
<div th:switch="${course.passed}">
<span th:case="true">пройден</span>
<span th:case="false">не пройден</span>
</div>
</td>
<td>
<form th:action="@{/courses/view}" th:method="post">
<input type="hidden" name="courseid" th:value="${course.id}">
<input type="hidden" name="accountid" th:value="${account.id}">
<input type="submit" value=">>>">
</form>
</td>
</tr>
</tbody>
</table>

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

@ -1,34 +1,8 @@ @@ -1,34 +1,8 @@
<!-- Коллекция фрагментов, предоставляющих инструменты управления формами -->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<div th:fragment="moodle">
<hr>
<!-- отправляем наименование компании и наименование должности
для перехода на целевой курс -->
<form th:action="@{/}" th:method="post">
<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>
<option value="2">монтажник</option>
<option value="3">специалист ПТО</option>
<option value="4">дефектоскопист</option>
</select>
<br>
<input type="submit" value="Перейти к moodle">
</form>
</div>
<!-- регистрация -->
<div th:fragment="exam">
<hr>
<p>Укажите данные для создания нового задания</p>
@ -57,6 +31,7 @@ @@ -57,6 +31,7 @@
</form>
</div>
<!-- авторизация -->
<div th:fragment="auth">
<!-- Отправляем запрос с параметром code
открываем существующую попытку -->
@ -67,11 +42,21 @@ @@ -67,11 +42,21 @@
</form>
</div>
<!-- выход / сброс сессии -->
<div th:fragment="logout">
<hr>
<form th:action="@{/logout}" th:method="get">
<input type="submit" value="выйти (сбросить сессию)">
</form>
</div>
<!-- переход к опросу -->
<div th:fragment="gotoQuiz(accountid)">
<hr>
<form th:action="@{/quiz}" th:method="get">
<input type="hidden" th:value="${accountid}" th:name="accountid"/>
<input type="submit" value="ПЕРЕЙТИ К ОПРОСУ"/>
</form>
</div>
</body>
</html>

5
main/src/main/resources/templates/fragments/course.html

@ -1,10 +1,11 @@ @@ -1,10 +1,11 @@
<!-- Коллекция фрагментов для построения страницы курса -->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<div th:fragment="main">
<div th:fragment="main(id)">
<hr>
<zero-md th:src="@{/content/courses/1/main.md}"></zero-md>
<zero-md th:src="@{/content/courses/{id}/main.md (id=${id})}"></zero-md>
</div>
</body>
</html>

11
main/src/main/resources/templates/fragments/quiz.html

@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
<!-- Коллекция фрагментов для построения страницы опроса -->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<div th:fragment="main">
<hr>
<h1>ОПРОС</h1>
</div>
</body>
</html>

29
main/src/main/resources/templates/quiz.html

@ -0,0 +1,29 @@ @@ -0,0 +1,29 @@
<!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-account</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>
<style>
.code {
color: red;
font-weight: bold;
font-size: 300%;
}
</style>
</head>
<header>
<!-- Информация об аккаунте: id, organization, position -->
<div th:insert="~{fragments/account :: info(account=${account})}"></div>
</header>
<body>
<!-- опрос -->
<div th:insert="~{fragments/quiz :: main}"></div>
</body>
<footer>
<div th:insert="~{fragments/common/footer :: copy}"></div>
</footer>
</html>

BIN
out/docs/erd/main/main.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 KiB

Loading…
Cancel
Save