jichoi / lms_front star
guntaek 10-21
20241021 김건택 선생님페이지 헤더 메뉴, 사이드, 학생리스트, 지문 리스트, 교재 리스트 수정
@0bbd6716b0ce35f01a3d7f6a212fb136de0758cd
 
client/views/layout/Header_t.vue (added)
+++ client/views/layout/Header_t.vue
@@ -0,0 +1,267 @@
+<template>
+  <div class="header flex justify-between align-center header-box">
+    <div>
+      <router-link to="/MyPlan.page">
+        <div class="logo">
+          <img src="../../resources/img/new_img/logo_v2.png" alt="" />
+        </div>
+      </router-link>
+    </div>
+    <div class="flex align-center">
+      <!-- <Menu :currentRoute="$route.path"></Menu> -->
+      <div class="notice" @click="buttonSearch">
+        <img src="../../resources/img/icon2.png" alt="" />
+        <p>{{ unCheck }}</p>
+      </div>
+      <img src="../../resources/img/new_img/profile_img.png" alt="" />
+      <div class="look-btn" @click="logout">
+        <img src="../../resources/img/new_img/icon/logout_icon.png" alt="" />
+      </div>
+      <div class="popup-wrap" v-show="searchOpen">
+        <div class="popup-box">
+          <div class="flex mb10 justify-between">
+            <p class="popup-title">알림</p>
+            <button type="button" class="popup-close-btn" @click="closeBtn">
+              <svg-icon
+                type="mdi"
+                :path="mdiWindowClose"
+                class="close-btn"
+              ></svg-icon>
+            </button>
+          </div>
+          <article
+            class="flex justify-between mt20"
+            v-for="item in dataList"
+            :key="item.id"
+            :class="{ 'selected-row': selectedRow == item.dataList }"
+          >
+            <img
+              style="width: fit-content"
+              src="../../resources/img/img200_13p.png"
+              alt=""
+            />
+            <p class="title1 ml20" style="width: 60%">{{ item.bbsTtl }}</p>
+            <button
+              @click="buttonSearch2(item)"
+              type="button"
+              title="글쓰기"
+              class="new-btn"
+            >
+              자세히 보기
+            </button>
+          </article>
+          <article
+            class="table-pagination flex justify-center align-center mb20 mt30"
+            style="gap: 10px"
+          >
+            <button @click="previousPage" :disabled="page === 1">이전</button>
+            <button class="selected-btn">{{ page }}</button>
+            <button @click="nextPage" :disabled="page === totalPages">
+              다음
+            </button>
+          </article>
+        </div>
+      </div>
+      <div class="popup-wrap popup2" v-show="searchOpen2">
+        <div class="popup-box">
+          <div class="flex mb10 justify-between">
+            <p class="popup-title">알림 자세히 보기</p>
+            <button type="button" class="popup-close-btn" @click="closeBtn2">
+              <svg-icon
+                type="mdi"
+                :path="mdiWindowClose"
+                class="close-btn"
+              ></svg-icon>
+            </button>
+          </div>
+          <div class="board-wrap">
+            <div class="flex align-center">
+              <label for="" class="title2">{{ boardData.bbsTtl }}</label>
+            </div>
+            <hr />
+            <!-- <textarea readonly name="" id="">{{ boardData.bbsCnt }}</textarea> -->
+          </div>
+          <div class="flex justify-center mt20">
+            <button
+              type="button"
+              title="확인"
+              class="new-btn"
+              @click="closeBtn2"
+            >
+              확인
+            </button>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import SvgIcon from "@jamescoyle/vue-icon";
+import { mdiMagnify, mdiWindowClose } from "@mdi/js";
+import axios from "axios";
+import Menu from "./Menu.vue";
+export default {
+  data() {
+    return {
+      mdiWindowClose: mdiWindowClose,
+      showModal: false,
+      searchOpen: false,
+      searchOpen2: false,
+
+      // 게시글 정보
+      dataList: [],
+      totalBoard: null,
+      selectedRow: "",
+      unCheck: null,
+
+      boardData: [],
+
+      // 페이징 정보
+      page: 1,
+      pageSize: 2,
+      totalpages: null,
+
+      // 사용자 정보
+      userId: "USID_000000000000006",
+      stdId: "",
+    };
+  },
+  methods: {
+    closeModal() {
+      this.showModal = false;
+    },
+    buttonSearch() {
+      this.searchOpen = true;
+    },
+    buttonSearch2(item) {
+      const vm = this;
+      this.searchOpen2 = true;
+      this.boardData = item;
+
+      axios({
+        url: "/board/boardStudentCheck.json",
+        method: "post",
+        headers: {
+          "Content-Type": "application/json; charset=UTF-8",
+        },
+        data: {
+          bbsId: item.bbsId,
+          stdId: vm.stdId,
+        },
+      })
+        .then(function (res) {
+          vm.boardList();
+        })
+        .catch(function (error) {
+          console.log("result - error : ", error);
+        });
+    },
+    closeBtn() {
+      this.searchOpen = false;
+    },
+    closeBtn2() {
+      this.searchOpen2 = false;
+    },
+
+    logout() {
+      const result = confirm("로그아웃 하시겠습니까?");
+      if (result) {
+        this.$store.dispatch("logout");
+        this.goToPage("login");
+      } else {
+        return;
+      }
+    },
+    goToPage(page) {
+      this.$router.push({ name: page });
+    },
+
+    // 공지 조회
+    boardList() {
+      const vm = this;
+      axios({
+        url: "/board/boardStudentList.json",
+        method: "post",
+        headers: {
+          "Content-Type": "application/json; charset=UTF-8",
+        },
+        data: { page: vm.page, pageSize: vm.pageSize, userId: vm.userId },
+      })
+        .then(function (res) {
+          vm.dataList = res.data.result[0].boardClass[0].board;
+          vm.userNm = res.data.result[0].userNm;
+          vm.userId = res.data.result[0].userId;
+          vm.unCheck = res.data.unCheck;
+          vm.stdId =
+            res.data.result[0].boardClass[0].board[0].boardStudent[0].stdId;
+          vm.totalBoard = res.data.totalBoard;
+          vm.totalPages = Math.ceil(vm.totalBoard / vm.pageSize);
+        })
+        .catch(function (error) {
+          console.log("result - error : ", error);
+        });
+    },
+
+    previousPage() {
+      if (this.page > 1) {
+        this.page -= 1;
+        this.boardList();
+      }
+    },
+
+    nextPage() {
+      if (this.page < this.totalPages) {
+        this.page += 1;
+        this.boardList();
+      }
+    },
+  },
+  watch: {},
+  computed: {},
+  components: {
+    SvgIcon,
+    Menu: Menu,
+  },
+  mounted() {
+    console.log("Header mounted");
+    this.boardList();
+  },
+};
+</script>
+<style scoped>
+.popup-wrap {
+  position: fixed;
+  background-color: transparent;
+  width: fit-content;
+  height: fit-content;
+  z-index: 10;
+}
+
+.popup-box {
+  top: 300px;
+  left: 62%;
+}
+
+.popup2 .popup-box {
+  top: 450px;
+  left: 38%;
+}
+
+/* 
+.header-box {
+    background-color: white;
+    padding: 10px 50px;
+    box-shadow: rgba(14, 63, 126, 0.04) 0px 0px 0px 1px, rgba(42, 51, 69, 0.04) 0px 1px 1px -0.5px,
+        rgba(42, 51, 70, 0.04) 0px 3px 3px -1.5px, rgba(42, 51, 70, 0.04) 0px 6px 6px -3px,
+        rgba(14, 63, 126, 0.04) 0px 12px 12px -6px, rgba(14, 63, 126, 0.04) 0px 24px 24px -12px;
+} */
+
+.header-box {
+  background-color: #ffffff80;
+  padding: 10px 50px;
+  /* box-shadow: rgba(14, 63, 126, 0.04) 0px 0px 0px 1px, rgba(42, 51, 69, 0.04) 0px 1px 1px -0.5px, rgba(42, 51, 70, 0.04) 0px 3px 3px -1.5px, rgba(42, 51, 70, 0.04) 0px 6px 6px -3px, rgba(14, 63, 126, 0.04) 0px 12px 12px -6px, rgba(14, 63, 126, 0.04) 0px 24px 24px -12px; */
+  backdrop-filter: blur(10px);
+}
+</style>
client/views/layout/Side_t.vue
--- client/views/layout/Side_t.vue
+++ client/views/layout/Side_t.vue
@@ -1,6 +1,6 @@
 <template>
     <div class="side_t side">
-        <div class="logo mb25"><img src="../../resources/img/logo2.png" alt=""></div>
+        <!-- <div class="logo mb25"><img src="../../resources/img/logo2.png" alt=""></div> -->
         <div class=" mb30">
             <div>
                 <img src="../../resources/img/img16_s.png" alt="">
@@ -73,4 +73,13 @@
         console.log('Menu mounted');
     }
 }
-</script>
(파일 끝에 줄바꿈 문자 없음)
+</script>
+
+
+<style scoped>
+.side {
+    max-height: 100vh; /* 사이드바가 화면의 높이를 넘지 않도록 설정 */
+    overflow-y: auto; /* 컨텐츠가 많을 경우 스크롤바 추가 */
+}
+
+</style>
(파일 끝에 줄바꿈 문자 없음)
client/views/pages/teacher/Main_t.vue
--- client/views/pages/teacher/Main_t.vue
+++ client/views/pages/teacher/Main_t.vue
@@ -2,7 +2,7 @@
     <div class="flex justify-between" style="height: 100%;">
        <Side_t></Side_t>
        <div style="padding: 15px 60px 120px 0px ">
-        <Header></Header>
+        <Header_t></Header_t>
           <div class="main-wrap">
               <router-view />
           </div>
@@ -12,7 +12,7 @@
 </template>
 
 <script>
-import Header from '../../layout/Header.vue';
+import Header_t from '../../layout/Header_t.vue';
 import Menu from '../../layout/Menu.vue';
 import Side_t from '../../layout/Side_t.vue';
 
@@ -31,7 +31,7 @@
 
   },
   components: {
-      Header: Header,
+      Header_t: Header_t,
     Menu: Menu,
     // Footer:Footer,
     Side_t:Side_t,
client/views/pages/teacher/StudentList.vue
--- client/views/pages/teacher/StudentList.vue
+++ client/views/pages/teacher/StudentList.vue
@@ -1,8 +1,11 @@
 <template>
     <div class="title-box flex justify-between mb40">
         <p class="title">게시판</p>
-        <select name="" id="">
-            <option value="">A반</option>
+        <select name="" id="" v-model="selectedClass" @click="fetchStudents">
+            <option value="" disabled selected>반을 선택하세요</option>
+            <option v-for="sClass in classesList" :key="sClass.sclsId" :value="sClass.sclsId">
+                {{ sClass.sclsNm }}
+            </option>
         </select>
     </div>
     <div class="flex justify-end mb20">
@@ -25,24 +28,25 @@
                 <td>No.</td>
                 <td>학년</td>
                 <td>반</td>
-                <td>성별</td>
                 <td>이름</td>
             </thead>
             <tbody>
-                <tr @click="goToPage('StudentDetail')">
-                    <td></td>
-                    <td></td>
-                    <td></td>
-                    <td></td>
-                    <td></td>
+                <!-- StudentDetail로 갈때 stdId? userId? -->
+                <tr v-for="(student, index) in students" :key="index" class="student"
+                    @click="goToPage('StudentDetail')">
+                    <td>{{ index + 1 + (currentPage - 1) * pageSize }}</td>
+                    <td>{{ student.grd_no }}</td>
+                    <td>{{ student.scls_nm }}</td>
+                    <td>{{ student.user_nm }}</td>
                 </tr>
             </tbody>
         </table>
         <article class="table-pagination flex justify-center align-center mb20 mt30" style="gap: 10px;">
             <button><img src="../../../resources/img/btn27_90t_normal.png" alt=""></button>
-            <button class="selected-btn">1</button>
-            <button>2</button>
-            <button>3</button>
+            <button v-for="page in totalPages" :key="page" @click="changePage(page)"
+                :class="{ 'selected-btn': currentPage === page }">
+                {{ page }}
+            </button>
             <button><img src="../../../resources/img/btn28_90t_normal.png" alt=""></button>
         </article>
         <div class="flex justify-end ">
@@ -82,15 +86,16 @@
                             <td></td>
                             <td></td>
                             <td></td>
-                            <td><input type="checkbox" class="ui-checkbox"></td>
                         </tr>
+                        <td><input type="checkbox" class="ui-checkbox"></td>
                     </tbody>
                 </table>
                 <article class="table-pagination flex justify-center align-center mb20 mt30" style="gap: 10px;">
                     <button><img src="../../../resources/img/btn27_90t_normal.png" alt=""></button>
-                    <button class="selected-btn">1</button>
-                    <button>2</button>
-                    <button>3</button>
+                    <button v-for="page in totalPages" :key="page" @click="changePage(page)"
+                        :class="{ 'selected-btn': currentPage === page }">
+                        {{ page }}
+                    </button>
                     <button><img src="../../../resources/img/btn28_90t_normal.png" alt=""></button>
                 </article>
                 <div class="flex justify-end ">
@@ -113,18 +118,86 @@
 <script>
 import SvgIcon from '@jamescoyle/vue-icon';
 import { mdiMagnify, mdiWindowClose } from '@mdi/js';
+import axios from 'axios';
 
 
 export default {
     data() {
         return {
+            classesList: [],
+
             mdiMagnify: mdiMagnify,
             mdiWindowClose: mdiWindowClose,
             showModal: false,
             searchOpen: false,
+
+            selectedClass: "",
+
+            students: [],
+
+            currentPage: 1,
+            pageSize: 10,
+            totalStudents: 0,
         }
     },
     methods: {
+        selectClass(){
+            axios({
+                url: "/classes/selectClass.json",
+                method: "post",
+                headers: {
+                    "Content-Type": "application/json; charset=UTF-8",
+                },
+                data: {
+                    userId: "2"
+                },
+            })
+            .then((res) => {
+                if (res.data.status === "success") {
+                console.log("classesList - response(조회) : ", res.data.data);
+                this.classesList = res.data.data;
+                } else {
+                    console.log("조회에 실패했습니다: ", res.data);
+                    alert("조회에 실패했습니다.")
+                }
+            }).catch((err) => {
+                console.log("classesList - error(조회) : ", err);
+                alert("조회에 오류가 발생했습니다.");
+            });
+        },
+
+        fetchStudents() {
+            const idx = (this.currentPage - 1) * this.pageSize;
+            axios({
+                url: "/userclass/find.json",
+                method: "post",
+                headers: {
+                    "Content-Type": "application/json; charset=UTF-8",
+                },
+                data: {
+                    "pageSize": this.pageSize,
+                    "startIndex": idx,
+                    "sclsId": this.selectedClass
+                },
+            })
+                .then(response => {
+                    console.log("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>",response.data.students);
+                    this.students = response.data.students;
+                    this.totalStudents = response.data.totalStudent;
+                })
+                .catch(error => {
+                    console.error("fetchStudents - error: ", error);
+                    alert("조회 중 오류가 발생했습니다.");
+                });
+        },
+
+        changePage(page) {
+            if (page > 0 && page <= this.totalPages) {
+                this.currentPage = page;
+                this.fetchStudents();
+            }
+        },
+
         goToPage(page) {
             this.$router.push({ name: page });
         },
@@ -158,13 +231,17 @@
 
     },
     computed: {
-
+        totalPages() {
+            console.log("totalPages@@@@@@@@@@@@@@@@@@@@@@@")
+            return Math.ceil(this.totalStudents / this.pageSize);
+        }
     },
     components: {
         SvgIcon
     },
     mounted() {
         console.log('Main2 mounted');
+        this.selectClass();
     }
 }
 </script>
(파일 끝에 줄바꿈 문자 없음)
client/views/pages/teacher/TextList.vue
--- client/views/pages/teacher/TextList.vue
+++ client/views/pages/teacher/TextList.vue
@@ -122,6 +122,7 @@
         },
         selectUnit(unitId) {
             this.selectedUnit = unitId;
+            this.currentPage = 1;
             this.fetchData();  
         },
         search() {
@@ -151,6 +152,7 @@
             })
                 .then(response => {
                     this.posts = response.data.list;
+                    console.log(response.data.totalText);
                     if (!this.searching || this.keyword === "") {
                         this.totalPosts = response.data.totalText;
                     } else if (this.searching) {
client/views/pages/teacher/textbook.vue
--- client/views/pages/teacher/textbook.vue
+++ client/views/pages/teacher/textbook.vue
@@ -33,9 +33,9 @@
             </div>
             <div class="search-wrap mb30">
               <input type="text" class="data-wrap" v-model="newBookName" placeholder="교재 이름을 입력하세요">
-              <button type="button" title="교재 검색" @click="insertBook">
+              <!-- <button type="button" title="교재 검색" @click="insertBook">
                 <img src="../../../resources/img/look_t.png" alt="">
-              </button>
+              </button> -->
             </div>
             <div class="flex justify-center">
               <button type="button" title="취소" class="new-btn mr10" @click="closeBtn">
Add a comment
List