diff --git a/src/main/java/osm/surveyor/task/city/TaskController.java b/src/main/java/osm/surveyor/task/city/TaskController.java index c03cfa1..93973a0 100644 --- a/src/main/java/osm/surveyor/task/city/TaskController.java +++ b/src/main/java/osm/surveyor/task/city/TaskController.java @@ -67,186 +67,80 @@ model.addAttribute("tasks", tasks); return "tasks"; } - - /** - * 「予約登録」 - * @param user - * @param model - * @param citycode - * @param meshcode - * @return - */ - @GetMapping("/task/reserve") - public String reserve(@AuthenticationPrincipal UserDetails user, - Model model, - @RequestParam(name="citycode") String citycode, - @RequestParam(name="meshcode") String meshcode) - { - model.addAttribute("command", "タスク登録"); - - // ログイン名を取得 - String loginName = ""; - if (user != null) { - loginName = user.getUsername(); - } - model.addAttribute("username", loginName); - - City city = cityRepository.getById(citycode); - model.addAttribute("citycode", citycode); - model.addAttribute("cityname", city.getCityname()); - model.addAttribute("meshcode", meshcode); - - CitymeshPK pk = new CitymeshPK(); - pk.setCitycode(citycode); - pk.setMeshcode(meshcode); - Citymesh mesh = meshRepository.getById(pk); - - Task pre = service.getTaskByMesh(citycode, meshcode); - if (pre != null) { - pre.setOperation(Operation.RESERVE); - pre.setUsername(loginName); - model.addAttribute("task", pre); - return "task"; - } - else { - // Taskが無い場合は生成する - String uuid = UUID.randomUUID().toString(); - Task task = new Task(); - task.setCurrentId(uuid); - task.setPreId(uuid); - task.setCitycode(citycode); - task.setMeshcode(meshcode); - task.setMesh(mesh); - task.setStatus(Status.PREPARATION); - task.setUsername(loginName); - task.setOperation(Operation.RESERVE); - model.addAttribute("task", task); - return "task"; - } - } - - /** - * 「タスク登録取り消し」 - * @param user - * @param model - * @param citycode - * @param meshcode - * @return - */ - @GetMapping("/task/cancel") - public String cancel(@AuthenticationPrincipal UserDetails user, - Model model, - @RequestParam(name="citycode") String citycode, - @RequestParam(name="meshcode") String meshcode) - { - model.addAttribute("command", "タスク登録取消"); - - // ログイン名を取得 - String loginName = ""; - if (user != null) { - loginName = user.getUsername(); - } - model.addAttribute("username", loginName); - - City city = cityRepository.getById(citycode); - model.addAttribute("citycode", citycode); - model.addAttribute("cityname", city.getCityname()); - model.addAttribute("meshcode", meshcode); - - CitymeshPK pk = new CitymeshPK(); - pk.setCitycode(citycode); - pk.setMeshcode(meshcode); - Citymesh mesh = meshRepository.getById(pk); - - Task pre = service.getTaskByMesh(citycode, meshcode); - if (pre != null) { - pre.setOperation(Operation.CANCEL); - pre.setUsername(loginName); - model.addAttribute("task", pre); - return "task"; - } - else { - // Taskが無い場合は生成する - String uuid = UUID.randomUUID().toString(); - Task task = new Task(); - task.setCurrentId(uuid); - task.setPreId(uuid); - task.setCitycode(citycode); - task.setMeshcode(meshcode); - task.setMesh(mesh); - task.setStatus(Status.ACCEPTING); - task.setUsername(loginName); - task.setOperation(Operation.CANCEL); - model.addAttribute("task", task); - - return "task"; - } - } /** - * 「作業完了」 - * @param user - * @param model + * 「タスク操作」 * @param citycode * @param meshcode + * @param task * @return */ - @GetMapping("/task/done") - public String done(@AuthenticationPrincipal UserDetails user, - Model model, - @RequestParam(name="citycode") String citycode, - @RequestParam(name="meshcode") String meshcode) - { - model.addAttribute("command", "作業終了"); - - // ログイン名を取得 - String loginName = ""; - if (user != null) { - loginName = user.getUsername(); - } - model.addAttribute("username", loginName); - - City city = cityRepository.getById(citycode); - model.addAttribute("citycode", citycode); - model.addAttribute("cityname", city.getCityname()); - model.addAttribute("meshcode", meshcode); - - CitymeshPK pk = new CitymeshPK(); - pk.setCitycode(citycode); - pk.setMeshcode(meshcode); - Citymesh mesh = meshRepository.getById(pk); - - Task pre = service.getTaskByMesh(citycode, meshcode); - if (pre != null) { - pre.setOperation(Operation.DONE); - pre.setUsername(loginName); - model.addAttribute("task", pre); - return "task"; - } - else { - // Taskが無い場合は生成する - String uuid = UUID.randomUUID().toString(); - Task task = new Task(); - task.setCurrentId(uuid); - task.setPreId(uuid); - task.setCitycode(citycode); - task.setMeshcode(meshcode); - task.setMesh(mesh); - task.setStatus(Status.IMPORTED); - task.setUsername(loginName); - task.setOperation(Operation.DONE); - model.addAttribute("task", task); - return "task"; - } - } - @GetMapping("/task/add") - public String addTask( + public String addTask(@AuthenticationPrincipal UserDetails user, + Model model, + @RequestParam(name="op") String op, @RequestParam(name="citycode") String citycode, - @RequestParam(name="meshcode") String meshcode, - @ModelAttribute Task task) + @RequestParam(name="meshcode") String meshcode) { - return "task"; + String next = "task"; + Operation operation = Operation.NOP; + Status baseStatus = Status.PREPARATION; + if (op.equals(Operation.RESERVE.toString())) { + model.addAttribute("command", "タスク予約"); + operation = Operation.RESERVE; + baseStatus = Status.PREPARATION; + } + else if (op.equals(Operation.CANCEL.toString())) { + model.addAttribute("command", "タスク予約取消"); + operation = Operation.CANCEL; + baseStatus = Status.ACCEPTING; + } + else if (op.equals(Operation.DONE.toString())) { + model.addAttribute("command", "編集完了"); + operation = Operation.DONE; + baseStatus = Status.IMPORTED; + next = "task_done"; + } + + // ログイン名を取得 + String loginName = ""; + if (user != null) { + loginName = user.getUsername(); + } + model.addAttribute("username", loginName); + + City city = cityRepository.getById(citycode); + model.addAttribute("citycode", citycode); + model.addAttribute("cityname", city.getCityname()); + model.addAttribute("meshcode", meshcode); + + CitymeshPK pk = new CitymeshPK(); + pk.setCitycode(citycode); + pk.setMeshcode(meshcode); + Citymesh mesh = meshRepository.getById(pk); + + Task pre = service.getTaskByMesh(citycode, meshcode); + if (pre != null) { + pre.setOperation(operation); + pre.setUsername(loginName); + model.addAttribute("task", pre); + return next; + } + else { + // 既存Taskが無い場合は生成する + String uuid = UUID.randomUUID().toString(); + Task task = new Task(); + task.setCurrentId(uuid); + task.setPreId(uuid); + task.setCitycode(citycode); + task.setMeshcode(meshcode); + task.setMesh(mesh); + task.setStatus(baseStatus); + task.setUsername(loginName); + task.setOperation(operation); + model.addAttribute("task", task); + return next; + } } @PostMapping("/task/process") @@ -256,6 +150,9 @@ { if (result.hasErrors()) { // エラーがある場合 + if (task.getOperation() == Operation.DONE) { + return "task_done"; + } return "task"; } service.add(task, user); @@ -264,6 +161,24 @@ } /** + * 400 Bad Request + * + * @param e + * @param model + * @param citycode + * @param meshcode + * @return + */ + @ExceptionHandler(TaskException.class) + public String taskExceptionHandler(TaskException e, Model model) + { + model.addAttribute("error", "400 Bad Request"); + model.addAttribute("message", e.toString()); + model.addAttribute("status", HttpStatus.BAD_REQUEST); + return exceptionHandler(e.getTask(), model); + } + + /** * 406 Not Acceptable * "ACCEPTIONGではないため予約できません" * @@ -279,24 +194,7 @@ model.addAttribute("error", "406 Not Acceptable"); model.addAttribute("message", e.toString()); model.addAttribute("status", HttpStatus.NOT_ACCEPTABLE); - - Task task = e.getTask(); - if (task == null) { - return "error"; - } - if (task.getOperation() == Operation.RESERVE) { - model.addAttribute("command", "タスク登録"); - } - else if (task.getOperation() == Operation.CANCEL) { - model.addAttribute("command", "タスク登録取消"); - } - else if (task.getOperation() == Operation.DONE) { - model.addAttribute("command", "作業完了"); - } - model.addAttribute("citycode", task.getCitycode()); - model.addAttribute("meshcode", task.getMeshcode()); - model.addAttribute("task", task); - return "task"; + return exceptionHandler(e.getTask(), model); } /** @@ -315,24 +213,30 @@ model.addAttribute("error", "409 Conflict"); model.addAttribute("message", e.toString()); model.addAttribute("status", HttpStatus.CONFLICT); - - Task task = e.getTask(); + return exceptionHandler(e.getTask(), model); + } + + private String exceptionHandler(Task task, Model model) { if (task == null) { return "error"; } if (task.getOperation() == Operation.RESERVE) { - model.addAttribute("command", "タスク登録"); + model.addAttribute("command", "タスク予約"); } else if (task.getOperation() == Operation.CANCEL) { - model.addAttribute("command", "タスク登録取消"); + model.addAttribute("command", "タスク予約取消"); } else if (task.getOperation() == Operation.DONE) { - model.addAttribute("command", "作業完了"); + model.addAttribute("command", "編集済み"); } model.addAttribute("citycode", task.getCitycode()); model.addAttribute("meshcode", task.getMeshcode()); model.addAttribute("task", task); + + if (task.getOperation() == Operation.DONE) { + return "task_done"; + } return "task"; } } diff --git a/src/main/java/osm/surveyor/task/city/TaskService.java b/src/main/java/osm/surveyor/task/city/TaskService.java index b0aa644..49eecad 100644 --- a/src/main/java/osm/surveyor/task/city/TaskService.java +++ b/src/main/java/osm/surveyor/task/city/TaskService.java @@ -62,34 +62,46 @@ } if (task.getOperation() == Operation.RESERVE) { if (ctask.getStatus() != Status.ACCEPTING) { - NotAcceptableException e = new NotAcceptableException("ステータスがACCEPTIONGではないためタスク登録できませんでした : "+ task.getOperation()); + NotAcceptableException e = new NotAcceptableException("ステータスがACCEPTIONGではないためタスク予約できませんでした : "+ task.getOperation()); e.setTask(task); throw e; } } else if (task.getOperation() == Operation.CANCEL) { if (ctask.getStatus() != Status.RESERVED) { - NotAcceptableException e = new NotAcceptableException("ステータスがRESERVEDではないためタスク登録できませんでした : "+ task.getOperation()); + NotAcceptableException e = new NotAcceptableException("ステータスがRESERVEDではないため予約取消できませんでした : "+ task.getOperation()); e.setTask(task); throw e; } if (!ctask.getUsername().equals(user.getUsername())) { - NotAcceptableException e = new NotAcceptableException("他のマッパーのタスクはCANCELできません"); + NotAcceptableException e = new NotAcceptableException("他のマッパーのタスク予約はCANCELできません"); e.setTask(task); throw e; } } else if (task.getOperation() == Operation.DONE) { - if (ctask.getStatus() != Status.RESERVED) { - NotAcceptableException e = new NotAcceptableException("タスク登録されていないためタスク完了できませんでした"); + // タスク予約していなくてもインポートできる + // 他のマッパーが予約していてもインポート可能 + String changeset = task.getChangeSet(); + if (changeset == null) { + TaskException e = new TaskException("変更セットNoが入力されていません"); e.setTask(task); throw e; } - if (!ctask.getUsername().equals(user.getUsername())) { - NotAcceptableException e = new NotAcceptableException("他のマッパーのタスクは完了できません"); + else if (changeset.isEmpty()) { + TaskException e = new TaskException("変更セットNoが入力されていません"); e.setTask(task); throw e; } + try { + Long.parseLong(changeset); + } + catch (NumberFormatException nfe) { + TaskException e = new TaskException("変更セットNoに数字以外の文字が入っています"); + e.setTask(task); + throw e; + } + } task.setPreId(ctask.getCurrentId()); task.setCurrentId(uuid); diff --git a/src/main/resources/i18n/messages_ja.properties b/src/main/resources/i18n/messages_ja.properties index ea165dc..655d648 100644 --- a/src/main/resources/i18n/messages_ja.properties +++ b/src/main/resources/i18n/messages_ja.properties @@ -29,7 +29,7 @@ # operation download = ダウンロード return = 戻る -reserve = タスク登録 -cancel = 登録取消 +reserve = タスク予約 +cancel = タスク予約取消 confirm = 確定 done = 編集完了 diff --git a/src/main/resources/static/custom/meshes.js b/src/main/resources/static/custom/meshes.js index 00f9178..bb61e02 100644 --- a/src/main/resources/static/custom/meshes.js +++ b/src/main/resources/static/custom/meshes.js @@ -105,7 +105,7 @@ var descriptionHTML = "<div>code: " + info.properties.id + "</div>" + "<div>version: " + info.properties.version + "</div>" + - "<div><a href='"+ site + dir + info.properties.path +"'>" + info.properties.path + "</a></div>"; + "<div><a href='/tasks?citycode=" + citycode + "&meshcode=" + info.properties.id +"'>タスク</a></div>"; element.innerHTML = descriptionHTML; __overlay.setPosition(coordinates); __map.addOverlay(__overlay); diff --git a/src/main/resources/static/custom/task.js b/src/main/resources/static/custom/task.js index e44a9f8..47f7326 100644 --- a/src/main/resources/static/custom/task.js +++ b/src/main/resources/static/custom/task.js @@ -17,35 +17,3 @@ const citycode = queryObject['citycode']; const meshcode = queryObject['meshcode']; const op = queryObject['op']; - -function loadMap() { - const div = document.getElementById("changeSet"); - - const lab1 = document.createElement("label"); - lab1.setAttribute("for", "changeSet"); - lab1.setAttribute("th:text", "#{changeSet}"); - - const inp1 = document.createElement("input"); - inp1.setAttribute("type", "text"); - inp1.setAttribute("class", "form-control"); - inp1.setAttribute("th:errorclass", "is-invalid"); - inp1.setAttribute("th:field", "*{changeSet}"); - - const d1 = document.createElement("div"); - d1.setAttribute("class", "invalid-feedback"); - d1.setAttribute("th:errors", "*{changeSet}"); - - const inp2 = document.createElement("input"); - inp2.setAttribute("type", "hidden"); - inp2.setAttribute("th:field", "*{changeSet}"); - inp2.setAttribute("th:value", "*{changeSet}"); - - if (op == "DONE") { - div.appendChild(lab1); - div.appendChild(inp1); - div.appendChild(d1); - } - else { - div.appendChild(inp2); - } -} diff --git a/src/main/resources/templates/task.html b/src/main/resources/templates/task.html index d975428..13f8ec4 100644 --- a/src/main/resources/templates/task.html +++ b/src/main/resources/templates/task.html @@ -6,9 +6,8 @@ <meta charset="UTF-8" th:remove="tag" /> <meta name="viewport" content="width=device-width,initial-scale=1" /> <link th:href="@{/webjars/bootstrap/css/bootstrap.min.css}" rel="stylesheet" /> - <script th:src="@{/custom/task.js}"></script> </head> -<body onload='loadMap()'> +<body> <!-- サイドバーの表示 --> <div layout:fragment="sidebar" th:replace="~{fragments/sidebar :: sidebar}"> @@ -90,6 +89,8 @@ </tbody> </table> + <hr> + <form th:action="@{/task/process}" method="post" novalidate> <input type="hidden" id="task" th:value="${task}" /> <input type="hidden" th:field="*{currentId}" th:value="*{currentId}" /> @@ -100,10 +101,7 @@ <input type="hidden" th:field="*{validator}" th:value="*{validator}" /> <input type="hidden" th:field="*{status}" th:value="*{status}" /> <input type="hidden" th:field="*{operation}" th:value="*{operation}" /> - - <div class="mb-3" id="changeSet"></div> - - <hr> + <input type="hidden" th:field="*{changeSet}" th:value="*{changeSet}" /> <p th:text="${error}"></p> <p th:text="${message}"></p> diff --git a/src/main/resources/templates/task_done.html b/src/main/resources/templates/task_done.html new file mode 100644 index 0000000..9b2f892 --- /dev/null +++ b/src/main/resources/templates/task_done.html @@ -0,0 +1,135 @@ +<!DOCTYPE html> +<html xmlns:th="http://www.thymeleaf.org" + xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" + layout:decorate="~{layout/layout}"> +<head> + <meta charset="UTF-8" th:remove="tag" /> + <meta name="viewport" content="width=device-width,initial-scale=1" /> + <link th:href="@{/webjars/bootstrap/css/bootstrap.min.css}" rel="stylesheet" /> +</head> +<body> + + <!-- サイドバーの表示 --> + <div layout:fragment="sidebar" th:replace="~{fragments/sidebar :: sidebar}"> + </div> + + + <!-- コンテンツの表示 --> + <div layout:fragment="content"> + <main class="offcanvas-outside bg-light"> + <div class="container-fluid"> + + <!-- トグルボタン --> + <div th:replace="~{fragments/sidebar :: toggler}"> + </div> + + <div class="row"> + <div class="col"> + + <div class="card shadow"> + <div class="card-header"> + <h6 class="text-navy my-2" th:text="${command}"></h6> + </div> + <div class="card-body" th:object="${task}"> + + <table class="table table-bordered"> + <thead> + <tr> + <th>item</th> + <th>value</th> + <th>comment</th> + </tr> + </thead> + <tbody> + <tr> + <td>currentId</td> + <td th:text="*{currentId}"></td> + <td></td> + </tr> + <tr> + <td>preId</td> + <td th:text="*{preId}"></td> + <td></td> + </tr> + <tr> + <td th:text="#{citycode}"></td> + <td th:text="${citycode}"></td> + <td th:text="${cityname}"></td> + </tr> + <tr> + <td th:text="#{meshcode}"></td> + <td th:text="*{meshcode}"></td> + <td></td> + </tr> + <tr> + <td th:text="#{username}"></td> + <td th:text="*{username}"></td> + <td></td> + </tr> + <tr> + <td th:text="#{validator}"></td> + <td th:text="*{validator}"></td> + <td></td> + </tr> + <tr> + <td th:text="#{changeSet}"></td> + <td th:text="*{changeSet}"></td> + <td></td> + </tr> + <tr> + <td th:text="#{status}"></td> + <td th:text="*{status}"></td> + <td></td> + </tr> + <tr> + <td th:text="#{operation}"></td> + <td th:text="*{operation}"></td> + <td></td> + </tr> + </tbody> + </table> + + <hr> + + <form th:action="@{/task/process}" method="post" novalidate> + <input type="hidden" id="task" th:value="${task}" /> + <input type="hidden" th:field="*{currentId}" th:value="*{currentId}" /> + <input type="hidden" th:field="*{preId}" th:value="*{preId}" /> + <input type="hidden" th:field="*{citycode}" th:value="*{citycode}" /> + <input type="hidden" th:field="*{meshcode}" th:value="*{meshcode}" /> + <input type="hidden" th:field="*{username}" th:value="*{username}" /> + <input type="hidden" th:field="*{validator}" th:value="*{validator}" /> + <input type="hidden" th:field="*{status}" th:value="*{status}" /> + <input type="hidden" th:field="*{operation}" th:value="*{operation}" /> + + <div class="mb-3"> + <label for="username" class="form-label"> + <span class="badge bg-danger">必須</span> + 変更セットNo + </label> + <input class="form-control" type="text" th:errorclass="is-invalid" th:field="*{changeSet}"> + <div class="invalid-feedback" th:errors="*{changeSet}"> + </div> + </div> + + <p th:text="${error}"></p> + <p th:text="${message}"></p> + + <a th:text="#{return}" th:href="@{/tasks?citycode={citycode}&meshcode={meshcode}(citycode=*{citycode},meshcode=*{meshcode})}" class="btn btn-navy"> + </a> + + <button class="btn btn-navy col-4"> + <i class="bi bi-pencil-square" th:text="${command}"></i> + </button> + + </form> + </div> + </div> + + </div> + </div> + </div> + </main> + </div> +</body> +</html> diff --git a/src/main/resources/templates/tasks.html b/src/main/resources/templates/tasks.html index 7917ece..6d24a5e 100644 --- a/src/main/resources/templates/tasks.html +++ b/src/main/resources/templates/tasks.html @@ -59,16 +59,19 @@ <td th:object="${mesh}" colspan='4'> <a th:text="#{return}" th:href="@{/mesh/{citycode}(citycode=*{citycode})}" class="btn btn-navy"> </a> - - <a th:href="@{/task/reserve?citycode={citycode}&meshcode={meshcode}(citycode=*{citycode},meshcode=*{meshcode})}" class="btn btn-navy"> + + <a th:text="#{download}" th:href="@{{site}{folder}/bldg/{path}(site=*{city.site},folder=*{city.folder},path=*{path})}" class="btn btn-navy"> + </a> + + <a th:href="@{/task/add?op=RESERVE&citycode={citycode}&meshcode={meshcode}(citycode=*{citycode},meshcode=*{meshcode})}" class="btn btn-navy"> <i class="bi bi-pencil-square" th:text="#{reserve}" ></i> </a> - <a th:href="@{/task/cancel?citycode={citycode}&meshcode={meshcode}(citycode=*{citycode},meshcode=*{meshcode})}" class="btn btn-navy"> + <a th:href="@{/task/add?op=CANCEL&citycode={citycode}&meshcode={meshcode}(citycode=*{citycode},meshcode=*{meshcode})}" class="btn btn-navy"> <i class="bi bi-pencil-square" th:text="#{cancel}"></i> </a> - <a th:href="@{/task/done?citycode={citycode}&meshcode={meshcode}(citycode=*{citycode},meshcode=*{meshcode})}" class="btn btn-navy"> + <a th:href="@{/task/add?op=DONE&citycode={citycode}&meshcode={meshcode}(citycode=*{citycode},meshcode=*{meshcode})}" class="btn btn-navy"> <i class="bi bi-pencil-square" th:text="#{done}"></i> </a> </td>