培训管理子系统开发4

整个项目预期的任务量 (任务量 = 所有工作的预期时间10天)和 目前已经花的时间 (所有记录的 ‘已经花费的时间’4天),还剩余的时间(所有工作的 ‘剩余时间’6天)


实现了试卷管理试卷的发布与浏览

package com.example.training.entity;

import javax.persistence.*;

@Entity
public class ExamPaper {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    private String name;

    @Column(columnDefinition = "TEXT")
    private String content;

    private String answer;
    private String score;

    public ExamPaper() {
    }

    public ExamPaper(Integer id, String name, String content, String answer, String score) {
        this.id = id;
        this.name = name;
        this.content = content;
        this.answer = answer;
        this.score = score;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public String getAnswer() {
        return answer;
    }

    public void setAnswer(String answer) {
        this.answer = answer;
    }

    public String getScore() {
        return score;
    }

    public void setScore(String score) {
        this.score = score;
    }
}
// 试卷管理
    @GetMapping("/papers")
    public String paperManage(HttpSession session, Model model) {
        if (!checkAdmin(session)) return "redirect:/login";
        model.addAttribute("papers", adminService.findAllExamPapers());
        return "admin/paper";
    }

    @PostMapping("/papers")
    public String savePaper(@ModelAttribute ExamPaper paper, HttpSession session) {
        if (!checkAdmin(session)) return "redirect:/login";
        adminService.saveExamPaper(paper);
        return "redirect:/admin/papers";
    }

    @PostMapping("/papers/delete/{id}")
    public String deletePaper(@PathVariable Integer id,
                              HttpSession session,
                              RedirectAttributes ra) {
        if (!checkAdmin(session)) return "redirect:/login";
        try {
            adminService.deleteExamPaper(id);
            ra.addFlashAttribute("success", "删除试卷成功");
        } catch (Exception e) {
            ra.addFlashAttribute("error", "删除失败:" + e.getMessage());
        }
        return "redirect:/admin/papers";
    }
    @PostMapping("/papers/score/{id}")
    public String updateScore(@PathVariable Integer id,
                              @RequestParam String score,
                              HttpSession session) {
        if (!checkAdmin(session)) return "redirect:/login";
        adminService.updateExamScore(id, score);
        return "redirect:/admin/papers";
    }
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
  <title>试卷管理</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <style>
    /* 基础样式 */
    body {
      font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
      background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%);
      margin: 0;
      min-height: 100vh;
      padding: 2rem;
    }

    .admin-container {
      background: rgba(255, 255, 255, 0.98);
      border-radius: 16px;
      box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15);
      padding: 2.5rem;
      max-width: 1200px;
      margin: 0 auto;
      backdrop-filter: blur(8px);
    }

    /* 提示信息 */
    .alert-container {
      position: fixed;
      top: 20px;
      right: 20px;
      max-width: 400px;
      z-index: 1000;
    }
    .alert {
      padding: 1rem 1.5rem;
      border-radius: 8px;
      margin-bottom: 1rem;
      font-weight: 500;
      transition: opacity 0.5s ease;
    }
    .alert.success {
      background: #e8f6ef;
      color: #2e7d32;
      border: 1px solid #a5d6a7;
    }
    .alert.error {
      background: #ffebee;
      color: #c62828;
      border: 1px solid #ffcdd2;
    }

    /* 返回链接 */
    .back-link {
      display: inline-flex;
      align-items: center;
      gap: 0.5rem;
      color: #2a5298;
      padding: 0.8rem 1.2rem;
      border-radius: 6px;
      background: rgba(42,82,152,0.1);
      transition: all 0.2s ease;
      text-decoration: none;
      margin-bottom: 2rem;
    }
    .back-link:hover {
      background: rgba(42,82,152,0.2);
      transform: translateX(-3px);
    }

    /* 标题样式 */
    h2 {
      color: #1e3c72;
      margin: 0 0 2rem;
      padding-bottom: 1rem;
      border-bottom: 3px solid #1e3c72;
      font-size: 2rem;
      letter-spacing: -0.5px;
    }

    /* 表单样式 */
    form {
      background: #f8f9fa;
      padding: 2rem;
      border-radius: 12px;
      margin-bottom: 3rem;
    }
    input, textarea {
      width: 100%;
      padding: 12px;
      margin: 10px 0;
      border: 2px solid #e0e0e0;
      border-radius: 8px;
      font-size: 1rem;
      transition: all 0.3s ease;
    }
    input:focus, textarea:focus {
      border-color: #1e3c72;
      box-shadow: 0 0 0 3px rgba(30,60,114,0.1);
      outline: none;
    }
    button[type="submit"] {
      background: #1e3c72;
      color: white;
      padding: 12px 24px;
      border: none;
      border-radius: 8px;
      cursor: pointer;
      font-weight: 600;
      transition: all 0.2s ease;
      margin-top: 1rem;
    }
    button[type="submit"]:hover {
      background: #2a5298;
      transform: translateY(-2px);
    }

    /* 表格样式 */
    .paper-table {
      width: 100%;
      border-collapse: collapse;
      background: white;
      border-radius: 12px;
      overflow: hidden;
      box-shadow: 0 2px 6px rgba(0,0,0,0.05);
    }
    th {
      background: linear-gradient(135deg, #1e3c72, #2a5298);
      color: white;
      padding: 1rem;
      font-weight: 600;
      text-align: left;
    }
    td {
      padding: 1rem;
      border-bottom: 1px solid #f0f4f8;
      vertical-align: top;
    }
    .content-cell div {
      max-height: 100px;
      overflow-y: auto;
      line-height: 1.6;
    }
    tr:hover {
      background-color: #f8fafc;
    }

    /* 删除按钮 */
    .delete-btn {
      background: #c62828 !important;
      color: white !important;
      padding: 8px 16px;
      border-radius: 6px;
      border: none;
      cursor: pointer;
      transition: all 0.2s ease;
    }
    .delete-btn:hover {
      background: #b71c1c !important;
      transform: translateY(-1px);
    }

    /* 响应式设计 */
    @media (max-width: 768px) {
      .admin-container {
        padding: 1.5rem;
      }
      form {
        padding: 1.5rem;
      }
      .paper-table {
        display: block;
        overflow-x: auto;
      }
      th, td {
        min-width: 200px;
      }
    }
    .alert-container {
      position: fixed;
      top: 80px;  /* 在导航栏下方 */
      right: 20px;
      z-index: 1000;
    }
  </style>
</head>
<body>
<!-- 提示信息容器 -->
<div class="alert-container">
  <div th:if="${success}" class="alert success" th:text="${success}"></div>
  <div th:if="${error}" class="alert error" th:text="${error}"></div>
</div>

<div class="admin-container">

  <h2>试卷管理系统</h2>

  <h3>新增试卷</h3>
  <form th:action="@{/admin/papers}" method="post">
    <input type="text" name="name" placeholder="试卷名称" required>
    <textarea name="content" placeholder="试卷内容" rows="4"></textarea>
    <input type="text" name="answer" placeholder="答案">
    <button type="submit">发布试卷</button>
  </form>

  <h3>试卷列表</h3>
  <table class="paper-table">
    <thead>
    <tr>
      <th style="width: 20%">试卷名称</th>
      <th style="width: 60%">试卷内容</th>
      <th style="width: 20%">操作</th>
    </tr>
    </thead>
    <tbody>
    <tr th:each="paper : ${papers}">
      <td th:text="${paper.name}"></td>
      <td class="content-cell">
        <div th:text="${paper.content}"></div>
      </td>
      <td>
        <form class="delete-form"
              th:action="@{/admin/papers/delete/{id}(id=${paper.id})}"
              method="post"
              onsubmit="return confirm('确定删除该试卷吗?');">
          <button type="submit" class="delete-btn">删除</button>
        </form>
      </td>
    </tr>
    </tbody>
  </table>
</div>

<script>
  /* 自动隐藏提示 */
  document.addEventListener('DOMContentLoaded', function() {
    const alerts = document.querySelectorAll('.alert');
    alerts.forEach(alert => {
      setTimeout(() => {
        alert.style.opacity = '0';
        setTimeout(() => alert.remove(), 1000);
      }, 3000);
    });
  });
</script>
</body>
</html>
posted @ 2025-04-19 20:41  霸王鸡  阅读(6)  评论(0)    收藏  举报