Pārlūkot izejas kodu

```
feat(api): 统一token存储键名

- 将localStorage中的'token'替换为'access_token',确保token清理的一致性

feat(LearningSystem): 实现评论功能

- 替换评论组件的静态数据为动态数据绑定
- 添加评论列表的分页显示功能
- 实现发送评论功能,包含输入验证和成功提示
- 添加评论内容的动态渲染
- 添加评论时间显示
- 添加课程ID变化的监听和自动刷新
- 注释掉分页组件,使用滚动加载
- 添加评论发送按钮样式优化
```

zhangningning 1 mēnesi atpakaļ
vecāks
revīzija
c1ed699460

+ 14 - 0
src/api/comment.js

@@ -0,0 +1,14 @@
+import request from './request.js'
+
+// 新增评论
+export function commentAdd(data = {}) {
+  return request.post('/comment',data)
+}
+// 获取评论列表
+export function getCommentList(data = {}) {
+  return request.get('/comment/list',data)
+}
+// 删除评论
+export function commentDel(data = {}) {
+  return request.del('/comment/'+data.id)
+}

+ 2 - 2
src/api/request.js

@@ -57,7 +57,7 @@ request.interceptors.response.use(
     if (code === 200) {
       return response.data
     } else if ([410000, 410001, 410002, 401, 403].includes(code)){
-      localStorage.removeItem('access_token')
+      localStorage.removeItem('token')
       window.location.href = '/login'
       
       return response.data
@@ -75,7 +75,7 @@ request.interceptors.response.use(
       switch (status) {
         case 401:
           // 未授权
-          localStorage.removeItem('access_token')
+          localStorage.removeItem('token')
           window.location.href = '/login'
           break
         case 403:

+ 64 - 23
src/pages/LearningSystem/components/pinglun.vue

@@ -1,42 +1,60 @@
 <template>
   <div class="pinglun">
-    <div class="font_size18 bold">{{$t('common.pinglun')}} (20)</div>
-    <div class="gap20 mt10">
+    <div class="font_size18 bold">{{$t('common.pinglun')}} ({{listTotal}})</div>
+    <div class="gap20 mt20 mb10">
       <el-avatar :size="32" :src="appStore.avatarDefault" />
       <div class="page-add flex_1">
-        <el-input v-model="comments" placeholder="请输入"  maxlength="500" style="width: 100%;"/>
+        <div class="flex-center-between">
+          <el-input v-model="comments" placeholder="请输入"  maxlength="500" style="width: 100%;flex:1"/>
+          <el-button type="primary" size="large" @click="handleSend" style="height:44px" class="gradient">发送</el-button>
+        </div>
       </div>
     </div>
-    <div class="flex-between font_size16 list_item" 
-    v-for="(item, index) in 4" :key="index">
-        <el-avatar :size="32" :src="appStore.avatarDefault" />
-      <div class="ml20 flex_1">
-        <div class="bold font_size14">这是名字</div>
-        <div class="gray mt5 line_height22">
-          这是视频简介内容这是视频简介内容这是视频简介内容这是视频简介内容这是视频简介内容这是视频简介内容这是视频简介内容这是视频简介内容这是视频简介内容这是视频简介内容这是视频简介内容这是视频简介内容
+    <div class="list">
+      <div class="flex-between font_size16 list_item" 
+      v-for="(item, index) in list" :key="index">
+        <el-avatar :size="32" :src="item.userAvatar || appStore.avatarDefault" />
+        <div class="ml20 flex_1">
+          <div class="flex-between">
+            <div class="bold font_size14">{{item.nickName}}</div>
+            <div class="gray font_size12">{{item.createTime}}</div>
+          </div>
+          <div class="gray mt5 line_height22">
+            {{item.content}}
+          </div>
         </div>
       </div>
     </div>
-    <Pagination 
+    <!-- <Pagination 
       :total="listTotal"
       :page-size="searchFom.pageSize"
       :current-page="searchFom.pageNum"
       @page-change="handlePageChange"
-    />
+    /> -->
   </div>
 </template>
 <script setup>
+import DGTMessage from '@/utils/message'
 import Pagination from '@/components/Pagination.vue'
-import { getCourseList } from '@/api/course.js'
-import { ref, onMounted,reactive } from 'vue'
+import { getCommentList,commentAdd } from '@/api/comment.js'
+import { ref, onMounted,reactive,watch } from 'vue'
 import { useAppStore } from '@/pinia/appStore'
 const appStore = useAppStore()
-defineProps({
+const props = defineProps({
   info: {
     type: Object,
     default: () => ({})
   }
 })
+
+//监听props.info.courseId变化
+watch(() => props.info.courseId, (newVal, oldVal) => {
+  if(newVal !== oldVal){
+    getList('init');
+  }
+})
+
+
 const comments = ref('');
 const listTotal = ref(0);
 const searchFom = reactive({
@@ -45,9 +63,7 @@ const searchFom = reactive({
 })
 const list = ref([]);
 
-onMounted(() => {
-  getList();
-});
+
 
 const handlePageChange = (page) => {
   searchFom.pageNum = page
@@ -60,16 +76,41 @@ const getList = async (type) => {
   if(type === 'init'){
     searchFom.pageNum = 1
   }
-  // const res = await getQuestList(searchFom)
-  // if(res.code === 200){
-  //   listTotal.value = res.total
-  //   list.value = res.rows
-  // }
+  const res = await getCommentList({
+    ...searchFom,
+    courseId: props.info.courseId
+  })
+  if(res.code === 200){
+    listTotal.value = res.rows.length
+    list.value = res.rows
+  }
+};
+// 发送评论
+const handleSend = async () => {
+  if(!comments.value){
+    DGTMessage.warning('请输入评论内容')
+    return
+  }
+  const res = await commentAdd({
+    courseId: props.info.courseId,
+    content: comments.value
+  })
+  if(res.code === 200){
+    DGTMessage.success('评论成功')
+    comments.value = ''
+    getList();
+  }
 };
 
+
+
 </script>
 <style scoped lang="scss">
   .pinglun{
+    .list{
+      max-height: 100vh;
+      overflow: auto;
+    }
     .list_item{
       cursor: pointer;
       padding: 15px 0;