<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      培訓管理子系統開發2

      整個項目預期的任務量 (任務量 = 所有工作的預期時間10天)和 目前已經花的時間 (所有記錄的 ‘已經花費的時間’2天),還剩余的時間(所有工作的 ‘剩余時間’8天)

      實現了課程管理功能的開發




      package com.example.training.entity;
      
      import javax.persistence.*;
      
      @Entity
      public class Course {
          @Id
          @GeneratedValue(strategy = GenerationType.IDENTITY)
          private Integer id;
      
          private String name;
          private String teacher;
      
          @Column(columnDefinition = "TEXT")
          private String content;
      
          public Course() {
          }
      
          public Course(Integer id, String name, String teacher, String content) {
              this.id = id;
              this.name = name;
              this.teacher = teacher;
              this.content = content;
          }
      
          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 getTeacher() {
              return teacher;
          }
      
          public void setTeacher(String teacher) {
              this.teacher = teacher;
          }
      
          public String getContent() {
              return content;
          }
      
          public void setContent(String content) {
              this.content = content;
          }
      }
      package com.example.training.entity;
      
      import javax.persistence.*;
      import java.time.LocalDateTime;
      @Table(name = "employee_course")
      @Entity
      public class EmployeeCourse {
          @Id
          @GeneratedValue(strategy = GenerationType.IDENTITY)
          private Integer id;
      
          @ManyToOne
          @JoinColumn(name = "employee_id", nullable = false)
          private User employee;
      
          @ManyToOne
          @JoinColumn(name = "course_id", nullable = false)
          private Course course;
      
          private boolean active = true;
          private LocalDateTime selectedAt = LocalDateTime.now();
      
          // Getters and Setters
          public Integer getId() { return id; }
          public User getEmployee() { return employee; }
          public void setEmployee(User employee) { this.employee = employee; }
          public Course getCourse() { return course; }
          public void setCourse(Course course) { this.course = course; }
          public boolean isActive() { return active; }
          public void setActive(boolean active) { this.active = active; }
          public LocalDateTime getSelectedAt() { return selectedAt; }
          public void setSelectedAt(LocalDateTime selectedAt) { this.selectedAt = selectedAt; }
      }
      
      
      // 課程管理
          @GetMapping("/courses")
          public String courseManage(HttpSession session, Model model) {
              if (!checkAdmin(session)) return "redirect:/login";
              model.addAttribute("courses", adminService.findAllCourses());
              return "admin/course";
          }
      
          @PostMapping("/courses")
          public String saveCourse(@ModelAttribute Course course, HttpSession session) {
              if (!checkAdmin(session)) return "redirect:/login";
              adminService.saveCourse(course);
              return "redirect:/admin/courses";
          }
      
          // 課程刪除
          @PostMapping("/courses/delete/{id}")
          public String deleteCourse(@PathVariable Integer id,
                                     HttpSession session,
                                     RedirectAttributes ra) {
              if (!checkAdmin(session)) return "redirect:/login";
      
              try {
                  adminService.deleteCourse(id);
                  ra.addFlashAttribute("success", "課程刪除成功");
              } catch (AdminService.ServiceException e) {
                  ra.addFlashAttribute("error", e.getMessage());
              } catch (Exception e) {
                  ra.addFlashAttribute("error", "系統錯誤:" + e.getMessage());
              }
              return "redirect:/admin/courses";
          }
      
      
      @GetMapping("/course")
          public String course(HttpSession session, Model model) {
              User employee = getCurrentEmployee(session);
      
              // 確保調用正確的服務方法
              List<Course> selectedCourses = employeeService.getSelectedCourses(employee.getId());
              List<Course> allCourses = employeeService.getAllCourses();
              List<ExamPaper> papers = employeeService.getAllPapers();
      
              // 正確設置模型屬性
              model.addAttribute("selectedCourses", selectedCourses);
              model.addAttribute("courses", allCourses);
              model.addAttribute("papers", papers);
      
              return "employee/course";
          }
      
      
          @PostMapping("/select-course")
          public String selectCourse(@RequestParam Integer courseId, HttpSession session) {
              User employee = getCurrentEmployee(session);
              employeeService.selectCourse(employee.getId(), courseId);
              return "redirect:/employee/course";
          }
      // 課程管理增強
          @PostMapping("/cancel-course")
          public String cancelCourse(@RequestParam Integer courseId,
                                     HttpSession session,
                                     RedirectAttributes ra) {
              try {
                  // 安全獲取當前用戶
                  User employee = (User) session.getAttribute("user");
                  if (employee == null || !employee.getRole().equals(User.Role.EMPLOYEE)) {
                      ra.addFlashAttribute("error", "請先登錄員工賬號");
                      return "redirect:/login";
                  }
      
                  employeeService.cancelCourse(employee.getId(), courseId);
                  ra.addFlashAttribute("success", "課程退選成功");
              } catch (ServiceException e) {
                  ra.addFlashAttribute("error", e.getMessage());
              } catch (Exception e) {
                  ra.addFlashAttribute("error", "系統錯誤:" + e.getMessage());
              }
              return "redirect:/employee/course";
          }
      
      <!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;
              }
      
              .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: 1000px;
                  margin: 0 auto;
                  backdrop-filter: blur(8px);
              }
      
              /* 提示信息 */
              .alert {
                  padding: 1rem 1.5rem;
                  border-radius: 8px;
                  margin: 1.5rem 0;
                  font-weight: 500;
              }
              .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: 2.5rem;
              }
              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);
              }
      
              /* 表格樣式 */
              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;
              }
              td {
                  padding: 1rem;
                  border-bottom: 1px solid #f0f4f8;
              }
              tr:hover {
                  background-color: #f8fafc;
              }
      
              /* 刪除按鈕 */
              .btn-delete {
                  background: #c62828 !important;
                  color: white !important;
                  padding: 8px 16px;
                  border-radius: 6px;
                  border: none;
                  cursor: pointer;
                  transition: all 0.2s ease;
              }
              .btn-delete:hover {
                  background: #b71c1c !important;
                  transform: translateY(-1px);
              }
      
              /* 響應式設計 */
              @media (max-width: 768px) {
                  .container {
                      padding: 1.5rem;
                  }
                  form {
                      padding: 1.5rem;
                  }
                  table {
                      display: block;
                      overflow-x: auto;
                  }
              }
      
              .alert-container {
                  position: fixed;
                  top: 80px;  /* 在導航欄下方 */
                  right: 20px;
                  z-index: 1000;
              }
          </style>
          <script>
              // 內容展開/收起功能
              function toggleContent(btn) {
                  const wrapper = btn.closest('.content-wrapper');
                  const preview = wrapper.querySelector('.content-preview');
                  const isExpanded = preview.style.whiteSpace === 'normal';
      
                  if(isExpanded) {
                      preview.style.whiteSpace = 'nowrap';
                      preview.style.overflow = 'hidden';
                      preview.style.textOverflow = 'ellipsis';
                      btn.textContent = '展開';
                  } else {
                      preview.style.whiteSpace = 'normal';
                      preview.style.overflow = 'visible';
                      preview.style.textOverflow = 'clip';
                      btn.textContent = '收起';
                  }
              }
          </script>
      
      </head>
      <body>
      <div class="container">
          <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>
      
          <h2>課程管理系統</h2>
      
          <h3>新增課程</h3>
          <form th:action="@{/admin/courses}" method="post">
              <input type="text" name="name" placeholder="課程名稱" required>
              <input type="text" name="teacher" placeholder="教師名稱" required>
              <textarea name="content" placeholder="課程內容" rows="4"></textarea>
              <button type="submit">添加課程</button>
          </form>
      
          <h3>課程列表</h3>
          <table>
              <thead>
              <tr>
                  <th>課程名稱</th>
                  <th>授課教師</th>
                  <th class="content-col">課程內容</th>
                  <th style="width:120px;">操作</th>
              </tr>
              </thead>
              <tbody>
              <tr th:each="course : ${courses}">
                  <td th:text="${course.name}"></td>
                  <td th:text="${course.teacher}"></td>
                  <!-- 課程內容(帶展開/收起功能) -->
                  <td class="content-cell">
                      <div class="content-wrapper">
                          <div class="content-preview"
                               th:data-fulltext="${course.content}"
                               th:text="${#strings.abbreviate(course.content, 50)}"></div>
                          <button class="btn-expand" onclick="toggleContent(this)">?</button>
                      </div>
                  </td>
                  <td>
                      <form th:action="@{/admin/courses/delete/{id}(id=${course.id})}"
                            method="post"
                            onsubmit="return confirm('確定刪除該課程嗎?');">
                          <button type="submit" class="btn-delete">刪除</button>
                      </form>
                  </td>
              </tr>
              </tbody>
          </table>
      </div>
      </body>
      </html>
      
      <!DOCTYPE html>
      <html xmlns:th="http://www.thymeleaf.org">
      <head>
          <title>課程中心</title>
          <style>
              :root {
                  --primary-blue: #1e3c72;
                  --secondary-blue: #2a5298;
                  --success-green: #2e7d32;
                  --error-red: #c62828;
              }
      
              body {
                  font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
                  background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%);
                  margin: 0;
                  min-height: 100vh;
              }
      
              .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: 2rem auto;
                  backdrop-filter: blur(8px);
              }
      
              /* 主標題樣式(深藍色文字+淺灰下劃線) */
              .main-title {
                  color: var(--primary-blue);
                  margin: 0 0 2rem;
                  padding-bottom: 1rem;
                  border-bottom: 2px solid #e0e0e0;
                  font-size: 1.8rem;
                  letter-spacing: -0.5px;
              }
      
              /* 子標題樣式(左側藍線) */
              .section-title {
                  color: var(--primary-blue);
                  font-size: 1.5rem;
                  padding-left: 1rem;
                  margin: 2rem 0;
                  border-left: 4px solid var(--primary-blue);
                  line-height: 1.2;
              }
      
              .course-grid {
                  display: grid;
                  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
                  gap: 2rem;
              }
      
              /* 課程卡片樣式 */
              .course-card {
                  background: white;
                  border-radius: 12px;
                  padding: 2rem;
                  box-shadow: 0 4px 12px rgba(30,60,114,0.1);
                  border: 1px solid #e0e0e0;
                  transition: transform 0.3s ease;
              }
      
              .course-card:hover {
                  transform: translateY(-5px);
              }
      
              /* 課程名稱樣式 */
              .course-name {
                  color: var(--primary-blue);
                  margin: 0 0 1rem;
                  font-size: 1.3rem;
                  font-weight: 600;
              }
      
              /* 教師信息樣式 */
              .course-teacher {
                  color: #65768c;
                  font-size: 0.95rem;
                  margin-bottom: 1.5rem;
              }
      
              /* 課程內容容器 */
              .course-content {
                  background: #f8f9fa;
                  border-radius: 8px;
                  padding: 1.2rem;
                  margin: 1.5rem 0;
                  border: 1px solid #e0e0e0;
                  position: relative;
              }
      
              /* 內容預覽樣式 */
              .content-preview {
                  white-space: nowrap;
                  overflow: hidden;
                  text-overflow: ellipsis;
                  color: #4a5568;
                  line-height: 1.6;
              }
      
              /* 展開按鈕 */
              .btn-expand {
                  position: absolute;
                  right: 10px;
                  bottom: 5px;
                  background: none;
                  border: none;
                  color: var(--primary-blue);
                  cursor: pointer;
                  font-size: 1.2rem;
              }
      
              /* 通用按鈕樣式 */
              .btn {
                  padding: 12px 24px;
                  border-radius: 8px;
                  font-weight: 600;
                  transition: all 0.2s ease;
                  display: inline-flex;
                  align-items: center;
                  gap: 8px;
              }
      
              /* 主按鈕 */
              .btn-primary {
                  background: var(--primary-blue);
                  color: white;
                  box-shadow: 0 4px 12px rgba(30,60,114,0.2);
              }
      
              .btn-primary:hover {
                  background: var(--secondary-blue);
                  transform: translateY(-2px);
              }
      
              /* 取消按鈕 */
              .btn-cancel {
                  background: var(--error-red);
                  color: white;
                  box-shadow: 0 4px 12px rgba(198,40,40,0.2);
              }
      
              .btn-cancel:hover {
                  background: #b71c1c;
                  transform: translateY(-2px);
              }
      
              /* 響應式設計 */
              @media (max-width: 768px) {
                  .admin-container {
                      padding: 1.5rem;
                      margin: 1rem;
                  }
                  .course-grid {
                      grid-template-columns: 1fr;
                  }
              }
          </style>
          <script>
              function toggleContent(btn) {
                  const wrapper = btn.closest('.course-content');
                  const preview = wrapper.querySelector('.content-preview');
                  const isExpanded = preview.style.whiteSpace === 'normal';
      
                  preview.style.whiteSpace = isExpanded ? 'nowrap' : 'normal';
                  preview.style.overflow = isExpanded ? 'hidden' : 'visible';
                  preview.style.textOverflow = isExpanded ? 'ellipsis' : 'clip';
                  btn.textContent = isExpanded ? '?' : '△';
              }
          </script>
      </head>
      <body>
      <div class="admin-container">
          <!-- 主標題(與截圖中的"考試成績查詢"樣式一致) -->
          <h1 class="main-title">課程管理系統</h1>
      
          <!-- 可選課程模塊 -->
          <div class="course-section">
              <h3 class="section-title">可選課程</h3>
              <div class="course-grid">
                  <div class="course-card" th:each="course : ${courses}">
                      <h4 class="course-name" th:text="${course.name}"></h4>
                      <p class="course-teacher">授課教師:<span th:text="${course.teacher}"></span></p>
      
                      <div class="course-content">
                          <div class="content-preview"
                               th:data-fulltext="${course.content}"
                               th:text="${#strings.abbreviate(course.content, 50)}"></div>
                          <button class="btn-expand" onclick="toggleContent(this)">?</button>
                      </div>
      
                      <form th:action="@{/employee/select-course}" method="post">
                          <input type="hidden" name="courseId" th:value="${course.id}">
                          <button type="submit" class="btn btn-primary">?? 立即選課</button>
                      </form>
                  </div>
              </div>
          </div>
      
          <!-- 已選課程模塊 -->
          <div class="course-section" th:if="${not #lists.isEmpty(selectedCourses)}">
              <h3 class="section-title">已選課程</h3>
              <div class="course-grid">
                  <div class="course-card" th:each="course : ${selectedCourses}">
                      <h4 class="course-name" th:text="${course.name}"></h4>
                      <p class="course-teacher">授課教師:<span th:text="${course.teacher}"></span></p>
      
                      <div class="course-content">
                          <div class="content-preview"
                               th:data-fulltext="${course.content}"
                               th:text="${#strings.abbreviate(course.content, 50)}"></div>
                          <button class="btn-expand" onclick="toggleContent(this)">?</button>
                      </div>
      
                      <form th:action="@{/employee/cancel-course}" method="post">
                          <input type="hidden" name="courseId" th:value="${course.id}">
                          <button type="submit" class="btn btn-cancel">?? 退選課程</button>
                      </form>
                  </div>
              </div>
          </div>
      </div>
      </body>
      </html>
      
      posted @ 2025-04-16 10:20  霸王雞  閱讀(8)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 九九热精彩视频在线免费| 日韩精品一区二区三区中文无码| 国产明星精品无码AV换脸| 五月综合激情婷婷六月| 欧美另类图区清纯亚洲| 沙湾县| 蜜桃AV抽搐高潮一区二区| 亚洲老熟女乱女一区二区| 国产SUV精品一区二区四| 777米奇色狠狠888俺也去乱| 国产360激情盗摄全集| 国产精品护士| 人妻激情乱人伦视频| 豆国产97在线 | 亚洲| japanese边做边乳喷| 久久国产精品精品国产色婷婷| 亚洲AVAV天堂AV在线网阿V| 亚洲三区在线观看内射后入| 国产亚洲精品第一综合| 亚洲午夜亚洲精品国产成人| 97成人碰碰久久人人超级碰oo| 亚洲AV永久无码天堂网一线| 性一交一黄一片| 国内精品伊人久久久影视| 亚洲精品成人一二三专区| 人妻中文字幕不卡精品| 午夜精品福利亚洲国产| 男人的天堂av一二三区| 色综合国产一区二区三区| 国产精品一区高清在线观看| 天天躁久久躁日日躁| 日韩理伦片一区二区三区| 国产综合精品一区二区在线| gogogo高清免费观看| 亚洲日本欧美日韩中文字幕| 精品视频福利| 好男人官网资源在线观看| 国产成人精品永久免费视频| 国产福利在线观看免费第一福利| 欧产日产国产精品精品| 亚洲成人高清av在线|