![](/assets/images/project_default_logo.png)
![](/assets/images/default-avatar-128.png)
240807 권민수 단어장 페이지 단어장 조회 기능 추가
@b58b810e0a710d306d46fa561bb294e97f3bd0d2
--- client/resources/css/common.css
+++ client/resources/css/common.css
... | ... | @@ -930,6 +930,10 @@ |
930 | 930 |
color: #fe0000; |
931 | 931 |
} |
932 | 932 |
|
933 |
+.gray { |
|
934 |
+ color: #999999; |
|
935 |
+} |
|
936 |
+ |
|
933 | 937 |
.cursor { |
934 | 938 |
cursor: pointer; |
935 | 939 |
} |
--- client/views/pages/teacher/VocaList.vue
+++ client/views/pages/teacher/VocaList.vue
... | ... | @@ -1,95 +1,184 @@ |
1 | 1 |
<template> |
2 | 2 |
<div class="title-box flex justify-between mb40"> |
3 |
- <p class="title">단어</p> |
|
3 |
+ <p class="title">단어장</p> |
|
4 | 4 |
<select name="" id=""> |
5 |
- <option value="">1단원</option> |
|
5 |
+ <option value="UNIT_000000000000001">1단원</option> |
|
6 | 6 |
</select> |
7 | 7 |
</div> |
8 |
- <div class="search-wrap flex justify-end mb20"> |
|
8 |
+ <div class="search-wrap flex justify-between mb20 align-center"> |
|
9 |
+ <div class="title2 gray">?단원 전체 목록</div> |
|
10 |
+ <div> |
|
9 | 11 |
<select name="" id="" class="mr10 data-wrap"> |
10 |
- <option value="">전체</option> |
|
12 |
+ <option value="">지문</option> |
|
13 |
+ <option value="">단어</option> |
|
11 | 14 |
</select> |
12 |
- <input type="text" placeholder="검색하세요."> |
|
13 |
- <button type="button" title="위원회 검색"> |
|
14 |
- <img src="../../../resources/img/look_t.png" alt=""> |
|
15 |
- </button> |
|
15 |
+ <input type="text" placeholder="검색하세요."> |
|
16 |
+ <button type="button" title="단어장 검색"> |
|
17 |
+ <img src="../../../resources/img/look_t.png" alt=""> |
|
18 |
+ </button> |
|
16 | 19 |
</div> |
17 |
- <div class="table-wrap"> |
|
18 |
- <table> |
|
19 |
- <thead> |
|
20 |
- <td>No.</td> |
|
21 |
- <td>단어</td> |
|
22 |
- <td>뜻</td> |
|
23 |
- <td>작성자</td> |
|
24 |
- <td>등록일</td> |
|
25 |
- </thead> |
|
26 |
- <tbody> |
|
27 |
- <tr @click="goToPage('noticeDetail')"> |
|
28 |
- <td></td> |
|
29 |
- <td></td> |
|
30 |
- <td></td> |
|
31 |
- <td></td> |
|
32 |
- <td></td> |
|
33 |
- </tr> |
|
34 |
- </tbody> |
|
35 |
- </table> |
|
36 |
- <article class="table-pagination flex justify-center align-center mb20 mt30" style="gap: 10px;"> |
|
37 |
- <button><img src="../../../resources/img/btn27_90t_normal.png" alt=""></button> |
|
38 |
- <button class="selected-btn">1</button> |
|
39 |
- <button>2</button> |
|
40 |
- <button>3</button> |
|
41 |
- <button><img src="../../../resources/img/btn28_90t_normal.png" alt=""></button> |
|
42 |
- </article> |
|
43 |
- <div class="flex justify-end "> |
|
44 |
- <button type="button" title="등록" class="new-btn" @click="goToPage('noticeInsert')"> |
|
45 |
- 등록 |
|
46 |
- </button> |
|
20 |
+ </div> |
|
21 |
+ <div class="table-wrap"> |
|
22 |
+ <table> |
|
23 |
+ <thead> |
|
24 |
+ <td>No.</td> |
|
25 |
+ <td>지문</td> |
|
26 |
+ <td>단어 목록</td> |
|
27 |
+ <td>작성자</td> |
|
28 |
+ <td>등록일</td> |
|
29 |
+ </thead> |
|
30 |
+ <tbody> |
|
31 |
+ <tr v-for="(wordBook, index) in dataList" :key="wordBook.wdBookId" @click="goToViewPage('noticeDetail')"> |
|
32 |
+ <td>{{ createNo(index) }}</td> |
|
33 |
+ <td>{{ wordBook.textTtl }}</td> |
|
34 |
+ <td>{{ wordBook.wordsPreview }}</td> |
|
35 |
+ <td>{{ wordBook.userId }}</td> |
|
36 |
+ <td>{{ '' }}</td> |
|
37 |
+ </tr> |
|
38 |
+ </tbody> |
|
39 |
+ </table> |
|
40 |
+ <article class="table-pagination flex justify-center align-center mb20 mt30" style="gap: 10px;"> |
|
41 |
+ <button @click="goToPage(currentPage - 1)"> |
|
42 |
+ <img src="../../../resources/img/btn27_90t_normal.png" alt=""> |
|
43 |
+ </button> |
|
44 |
+ <button v-for="page in paginationButtons" :key="page" @click="goToPage(page - 1)" :class="{ 'selected-btn': currentPage === page - 1 }"> |
|
45 |
+ {{ page }} |
|
46 |
+ </button> |
|
47 |
+ <button @click="goToPage(currentPage + 1)"> |
|
48 |
+ <img src="../../../resources/img/btn28_90t_normal.png" alt=""> |
|
49 |
+ </button> |
|
50 |
+ </article> |
|
51 |
+ <div class="flex justify-end "> |
|
52 |
+ <button type="button" title="등록" class="new-btn" @click="goToPage('noticeInsert')"> |
|
53 |
+ 등록 |
|
54 |
+ </button> |
|
47 | 55 |
</div> |
48 |
- </div> |
|
56 |
+ </div> |
|
49 | 57 |
</template> |
50 | 58 |
|
51 | 59 |
<script> |
52 | 60 |
import SvgIcon from '@jamescoyle/vue-icon'; |
53 |
-import { mdiMagnify} from '@mdi/js'; |
|
61 |
+import { mdiMagnify } from '@mdi/js'; |
|
62 |
+import axios from "axios"; |
|
54 | 63 |
|
55 | 64 |
|
56 | 65 |
export default { |
57 | 66 |
data () { |
58 | 67 |
return { |
59 | 68 |
mdiMagnify: mdiMagnify, |
69 |
+ dataList: [], |
|
70 |
+ currentPage: 0, |
|
71 |
+ itemsPerPage: 2, |
|
72 |
+ totalPosts: 0, |
|
73 |
+ unitId: "UNIT_000000000000001" |
|
60 | 74 |
} |
61 | 75 |
}, |
62 | 76 |
methods: { |
63 |
- goToPage(page) { |
|
64 |
- this.$router.push({ name: page }); |
|
65 |
- }, |
|
66 |
- showConfirm(type) { |
|
67 |
- let message = ''; |
|
68 |
- if (type === 'cancel') { |
|
69 |
- message = '삭제하시겠습니까?'; |
|
70 |
- } else if (type === 'reset') { |
|
71 |
- message = '초기화하시겠습니까?'; |
|
72 |
- } else if (type === 'save') { |
|
73 |
- message = '등록하시겠습니까?'; |
|
74 |
- } |
|
75 | 77 |
|
76 |
- if (confirm(message)) { |
|
77 |
- this.goBack(); |
|
78 |
+ dataSelectList() { |
|
79 |
+ const vm = this; |
|
80 |
+ axios({ |
|
81 |
+ url: "/wordbook/findByUnitId.json", |
|
82 |
+ method: "post", |
|
83 |
+ headers: { |
|
84 |
+ "Content-Type": "application/json; charset=UTF-8", |
|
85 |
+ }, |
|
86 |
+ data: { |
|
87 |
+ unitId: vm.unitId, |
|
88 |
+ page: vm.currentPage + 1, |
|
89 |
+ pageSize: vm.itemsPerPage |
|
90 |
+ }, |
|
91 |
+ }) |
|
92 |
+ .then(function (response) { |
|
93 |
+ console.log("dataList - response: ", response.data); |
|
94 |
+ const wordBooks = response.data.wordBooks; |
|
95 |
+ vm.totalPosts = response.data.totalWordBooks; |
|
96 |
+ |
|
97 |
+ // 지문 제목 및 단어 목록 가져오기 |
|
98 |
+ const fetchDataPromises = wordBooks.map(wordBook => { |
|
99 |
+ const textTitlePromise = axios.post("/text/selectOneText.json", { |
|
100 |
+ textId: wordBook.textId |
|
101 |
+ }).then(textResponse => { |
|
102 |
+ wordBook.textTtl = textResponse.data[0].text_ttl; |
|
103 |
+ }).catch(error => { |
|
104 |
+ console.error(`${wordBook.textId}으로 지문 제목 가져오기 실패: `, error); |
|
105 |
+ wordBook.textTtl = '제목값없음'; // 오류 시 기본값 설정 |
|
106 |
+ }); |
|
107 |
+ |
|
108 |
+ const wordsPromise = axios.post("/word/getWordsByBookId.json", { |
|
109 |
+ wdBookId: wordBook.wdBookId |
|
110 |
+ }).then(wordsResponse => { |
|
111 |
+ const words = wordsResponse.data.map(word => word.wdNm); |
|
112 |
+ wordBook.wordsPreview = vm.generateWordsPreview(words); |
|
113 |
+ }).catch(error => { |
|
114 |
+ console.error(`${wordBook.wdBookId}으로 단어 목록 가져오기 실패: `, error); |
|
115 |
+ wordBook.wordsPreview = '단어값없음'; // 오류 시 기본값 설정 |
|
116 |
+ }); |
|
117 |
+ |
|
118 |
+ return Promise.all([textTitlePromise, wordsPromise]); |
|
119 |
+ }); |
|
120 |
+ |
|
121 |
+ // 모든 데이터 가져오기 작업이 완료되면 dataList에 데이터 설정 |
|
122 |
+ Promise.all(fetchDataPromises).then(() => { |
|
123 |
+ vm.dataList = wordBooks; |
|
124 |
+ }); |
|
125 |
+ }) |
|
126 |
+ .catch(function (error) { |
|
127 |
+ console.log("dataList - error: ", error); |
|
128 |
+ alert("단어장 목록 조회에 오류가 발생했습니다."); |
|
129 |
+ }); |
|
130 |
+ }, |
|
131 |
+ generateWordsPreview(words) { |
|
132 |
+ const maxLength = 20; // 최대 표시 길이 설정 |
|
133 |
+ const wordString = words.join(', '); |
|
134 |
+ |
|
135 |
+ if (wordString.length > maxLength) { |
|
136 |
+ return wordString.substring(0, maxLength) + '...'; |
|
137 |
+ } else { |
|
138 |
+ return wordString; |
|
78 | 139 |
} |
79 | 140 |
}, |
80 |
- |
|
141 |
+ createNo(index) { |
|
142 |
+ return this.totalPosts - (this.currentPage * this.itemsPerPage + index); |
|
143 |
+ }, |
|
144 |
+ goToPage(page) { |
|
145 |
+ if (page < 0 || page >= this.totalPages) { |
|
146 |
+ return; |
|
147 |
+ } |
|
148 |
+ this.currentPage = page; |
|
149 |
+ this.dataSelectList(); |
|
150 |
+ }, |
|
151 |
+ goToViewPage(page) { |
|
152 |
+ this.$router.push({ name: page }); |
|
153 |
+ }, |
|
81 | 154 |
}, |
82 | 155 |
watch: { |
83 | 156 |
|
84 | 157 |
}, |
85 | 158 |
computed: { |
86 |
- |
|
159 |
+ totalPages() { |
|
160 |
+ return Math.ceil(this.totalPosts / this.itemsPerPage); |
|
161 |
+ }, |
|
162 |
+ paginationButtons() { |
|
163 |
+ let start = Math.max(0, this.currentPage - 2); |
|
164 |
+ let end = Math.min(start + 5, this.totalPages); |
|
165 |
+ |
|
166 |
+ if (end - start < 5) { |
|
167 |
+ start = Math.max(0, end - 5); |
|
168 |
+ } |
|
169 |
+ |
|
170 |
+ return Array.from({ length: end - start }, (_, i) => start + i + 1); |
|
171 |
+ }, |
|
172 |
+ startIndex() { |
|
173 |
+ return this.currentPage * this.itemsPerPage; |
|
174 |
+ } |
|
87 | 175 |
}, |
88 | 176 |
components:{ |
89 | 177 |
SvgIcon |
90 | 178 |
}, |
91 | 179 |
mounted() { |
92 |
- console.log('Main2 mounted'); |
|
180 |
+ console.log('Voca Book List Component mounted'); |
|
181 |
+ this.dataSelectList(); |
|
93 | 182 |
} |
94 | 183 |
} |
95 | 184 |
</script>(No newline at end of file) |
Add a comment
Delete comment
Once you delete this comment, you won't be able to recover it. Are you sure you want to delete this comment?