TeacherDetail.vue 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. <template>
  2. <div class="teacher-detail">
  3. <header class="teacher-header">
  4. <img :src="teacher.image" :alt="teacher.name" class="profile-image">
  5. <h1>{{ teacher.name }}</h1>
  6. </header>
  7. <section class="basic-info">
  8. <h2>基本信息</h2>
  9. <p style="white-space: pre-line"><strong>简介:</strong> <p></p> {{ teacher.profile }}</p>
  10. <p style="white-space: pre-line"><strong>本科课程:</strong> <p></p> {{ teacher.undergraduateCourse }}</p>
  11. <p style="white-space: pre-line"><strong>研究生课程:</strong> <p></p> {{ teacher.graduateCourse }}</p>
  12. <p style="white-space: pre-line"><strong>研究领域:</strong> <p></p> {{ teacher.researchField }}</p>
  13. <p><strong>邮箱:</strong> {{ teacher.email }}</p>
  14. <p><strong>电话:</strong> {{ teacher.phoneNumber }}</p>
  15. </section>
  16. <section class="additional-info">
  17. <CollapsibleSection title="专利" :expanded="expandedSections.patents">
  18. <div v-for="patent in teacher.patent" :key="patent.patentNum" class="info-item">
  19. <p><strong>专利号:</strong> {{ patent.patentNum }}</p>
  20. <p><strong>授权号:</strong> {{ patent.authorizationNum }}</p>
  21. <p><strong>证书号:</strong> {{ patent.certificateNum }}</p>
  22. <p><strong>日期:</strong> {{ patent.date }}</p>
  23. </div>
  24. <Pagination
  25. :current-page="patentPage"
  26. :total-items="patentTotal"
  27. :items-per-page="pageSize"
  28. @page-change="handlePatentPageChange"
  29. />
  30. </CollapsibleSection>
  31. <CollapsibleSection title="获奖" :expanded="expandedSections.awards">
  32. <div v-for="award in awards" :key="award.id" class="info-item">
  33. <p><strong>名称:</strong> {{ award.name }}</p>
  34. <p><strong>时间:</strong> {{ award.time }}</p>
  35. <img :src="award.image" :alt="award.name" class="info-image">
  36. </div>
  37. <Pagination
  38. :current-page="awardPage"
  39. :total-items="awardTotal"
  40. :items-per-page="pageSize"
  41. @page-change="handleAwardPageChange"
  42. />
  43. </CollapsibleSection>
  44. <CollapsibleSection title="论文" :expanded="expandedSections.theses">
  45. <div v-for="thesis in theses" :key="thesis.id" class="info-item">
  46. <p><strong>名称:</strong> {{ thesis.name }}</p>
  47. <p><strong>发表时间:</strong> {{ thesis.time }}</p>
  48. <a :href="thesis.website" target="_blank" class="info-link">查看详情</a>
  49. <img :src="thesis.image" :alt="thesis.name" class="info-image">
  50. <a :href="thesis.file" target="_blank" class="info-link">下载文件</a>
  51. </div>
  52. <Pagination
  53. :current-page="thesisPage"
  54. :total-items="thesisTotal"
  55. :items-per-page="pageSize"
  56. @page-change="handleThesisPageChange"
  57. />
  58. </CollapsibleSection>
  59. <CollapsibleSection title="著作" :expanded="expandedSections.works">
  60. <div v-for="work in works" :key="work.id" class="info-item">
  61. <p><strong>名称:</strong> {{ work.name }}</p>
  62. <p><strong>出版社:</strong> {{ work.press }}</p>
  63. <p><strong>出版时间:</strong> {{ work.time }}</p>
  64. <img :src="work.image" :alt="work.name" class="info-image">
  65. <a :href="work.file" target="_blank" class="info-link">下载文件</a>
  66. </div>
  67. <Pagination
  68. :current-page="workPage"
  69. :total-items="workTotal"
  70. :items-per-page="pageSize"
  71. @page-change="handleWorkPageChange"
  72. />
  73. </CollapsibleSection>
  74. </section>
  75. </div>
  76. </template>
  77. <script>
  78. import { ref, reactive, watch } from 'vue';
  79. import { useRoute } from 'vue-router';
  80. import { useTeachersStore } from '@/store/modules/teachers';
  81. import CollapsibleSection from '@/components/CollapsibleSection.vue';
  82. import Pagination from '@/components/Pagination.vue';
  83. import { getThesisPage, getWorksPage, getAwards } from '@/api/Open'
  84. export default {
  85. name: 'TeacherDetail',
  86. components: {
  87. CollapsibleSection,
  88. Pagination
  89. },
  90. setup() {
  91. const teachersStore = useTeachersStore();
  92. const route = useRoute();
  93. const teacherId = ref(route.params.id);
  94. const teacher = ref({});
  95. const awards = ref([]);
  96. const theses = ref([]);
  97. const works = ref([]);
  98. const pageSize = ref(12);
  99. const awardPage = ref(1);
  100. const awardTotal = ref(1);
  101. const thesisPage = ref(1);
  102. const thesisTotal = ref(1);
  103. const workPage = ref(1);
  104. const workTotal = ref(1);
  105. const patentPage = ref(1);
  106. const patentTotal = ref(1);
  107. const expandedSections = reactive({
  108. patents: false,
  109. awards: false,
  110. theses: false,
  111. works: false
  112. });
  113. const fetchTeacherData = async () => {
  114. try {
  115. await teachersStore.fetchTeacherDetails(teacherId.value); // 调用 Pinia 方法
  116. teacher.value = teachersStore.currentTeacher; // 从 store 获取教师信息
  117. patentTotal.value = teacher.value.patent ? teacher.value.patent.length : 0; // 计算专利数量
  118. } catch (error) {
  119. console.error('获取教师信息失败:', error);
  120. }
  121. };
  122. const fetchAwards = async () => {
  123. try {
  124. const response = await getAwards(awardPage.value, 12, null, teacherId.value);
  125. awards.value = response.data.records;
  126. awardTotal.value = response.data.total;
  127. } catch (error) {
  128. console.error('获取获奖信息失败:', error);
  129. }
  130. };
  131. const fetchTheses = async () => {
  132. try {
  133. const response = await getThesisPage(thesisPage.value, 12, null, teacherId.value);
  134. theses.value = response.data.records;
  135. thesisTotal.value = response.data.total;
  136. } catch (error) {
  137. console.error('获取论文信息失败:', error);
  138. }
  139. };
  140. const fetchWorks = async () => {
  141. try {
  142. const response = await getWorksPage(workPage.value, 12, null, teacherId.value);
  143. works.value = response.data.records;
  144. workTotal.value = response.data.total;
  145. } catch (error) {
  146. console.error('获取著作信息失败:', error);
  147. }
  148. };
  149. const handleAwardPageChange = (page) => {
  150. awardPage.value = page;
  151. fetchAwards();
  152. };
  153. const handleThesisPageChange = (page) => {
  154. thesisPage.value = page;
  155. fetchThesis();
  156. };
  157. const handleWorkPageChange = (page) => {
  158. workPage.value = page;
  159. fetchWorks();
  160. };
  161. const handlePatentPageChange = (page) => {
  162. patentPage.value = page;
  163. teacher.value.patent = teacher.value.patent.slice((page - 1) * pageSize.value, page * pageSize.value);
  164. };
  165. watch(teacherId, () => {
  166. fetchTeacherData();
  167. fetchAwards();
  168. fetchTheses();
  169. fetchWorks();
  170. }, { immediate: true });
  171. return {
  172. teacher,
  173. awards,
  174. theses,
  175. works,
  176. pageSize,
  177. awardPage,
  178. awardTotal,
  179. thesisPage,
  180. thesisTotal,
  181. workPage,
  182. workTotal,
  183. patentPage,
  184. patentTotal,
  185. expandedSections,
  186. handleAwardPageChange,
  187. handleThesisPageChange,
  188. handleWorkPageChange,
  189. handlePatentPageChange
  190. };
  191. }
  192. };
  193. </script>
  194. <style scoped>
  195. .teacher-detail {
  196. max-width: 1000px;
  197. margin: 0 auto;
  198. padding: 2rem;
  199. background-color: #f8f9fa;
  200. border-radius: 10px;
  201. box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
  202. }
  203. .teacher-header {
  204. display: flex;
  205. align-items: center;
  206. margin-bottom: 2rem;
  207. }
  208. .profile-image {
  209. width: 150px;
  210. height: 150px;
  211. object-fit: cover;
  212. border-radius: 50%;
  213. margin-right: 2rem;
  214. box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  215. }
  216. h1 {
  217. font-size: 2.5rem;
  218. color: #2c3e50;
  219. margin: 0;
  220. }
  221. h2 {
  222. font-size: 1.8rem;
  223. color: #34495e;
  224. margin-top: 0;
  225. margin-bottom: 1rem;
  226. border-bottom: 2px solid #3498db;
  227. padding-bottom: 0.5rem;
  228. }
  229. .basic-info, .additional-info {
  230. background-color: #ffffff;
  231. padding: 1.5rem;
  232. border-radius: 8px;
  233. margin-bottom: 2rem;
  234. box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
  235. }
  236. .info-item {
  237. margin-bottom: 1.5rem;
  238. padding-bottom: 1.5rem;
  239. border-bottom: 1px solid #e0e0e0;
  240. }
  241. .info-item:last-child {
  242. border-bottom: none;
  243. }
  244. .info-image {
  245. max-width: 100%;
  246. height: auto;
  247. border-radius: 4px;
  248. margin-top: 1rem;
  249. }
  250. .info-link {
  251. display: inline-block;
  252. margin-top: 0.5rem;
  253. color: #3498db;
  254. text-decoration: none;
  255. transition: color 0.3s ease;
  256. }
  257. .info-link:hover {
  258. color: #2980b9;
  259. }
  260. p {
  261. margin-bottom: 0.5rem;
  262. line-height: 1.6;
  263. }
  264. strong {
  265. color: #2c3e50;
  266. }
  267. .pagination {
  268. display: flex;
  269. justify-content: center;
  270. margin-top: 1.5rem;
  271. }
  272. /* Add any additional styles for the CollapsibleSection and Pagination components here */
  273. </style>