Jelajahi Sumber

```
feat(LearnNote): 实现课程笔记列表功能并优化UI显示

- 添加课程列表展示功能,显示课程封面、标题和简介
- 集成Xuxibiji组件用于显示具体笔记内容
- 实现课程项点击选择功能,动态切换笔记列表
- 添加空数据状态的分页组件显示
- 优化样式布局,增加卡片阴影效果

fix(Pagination): 修复空数据时的分页显示问题

- 在分页组件中添加空数据状态的空状态组件显示
- 解决total为0时的显示逻辑

fix(LearningSystem): 修复分页组件total参数绑定错误

- 将Pagination组件的total属性从searchFom.total改为listTotal

feat(mibiShop): 完成米币商城列表功能开发

- 实现商城商品列表的真实数据显示
- 集成API获取商品信息并展示图片、名称、价格
- 添加购买兑换功能和余额不足提示
- 优化分页大小从10调整为20条
- 增加国际化支持和路由跳转逻辑

refactor(xuxibiji): 优化笔记组件显示逻辑

- 添加课程ID存在时才显示添加按钮的条件渲染
```

zhangningning 1 bulan lalu
induk
melakukan
370b2a4ae5

+ 6 - 0
src/api/mall.js

@@ -0,0 +1,6 @@
+import request from './request.js'
+
+// 查询商城列表
+export function getMallList(data = {}) {
+  return request.get('/mall/list',data)
+}

+ 14 - 9
src/components/Pagination.vue

@@ -1,14 +1,19 @@
 <!-- src/components/Pagination.vue -->
 <template>
-  <div class="pagination-container">
-    <el-pagination
-      background
-      layout="prev, pager, next, total"
-      :total="total"
-      :page-size="pageSize"
-      :current-page="currentPage"
-      @current-change="handleCurrentChange"
-    />
+  <div>
+    <div v-if="total === 0" >
+      <el-empty :image-size="200" />
+    </div>
+    <div class="pagination-container">
+      <el-pagination
+        background
+        layout="prev, pager, next, total"
+        :total="total"
+        :page-size="pageSize"
+        :current-page="currentPage"
+        @current-change="handleCurrentChange"
+      />
+    </div>
   </div>
 </template>
 

+ 25 - 18
src/pages/LearnNote/LearnNote.vue

@@ -3,31 +3,32 @@
     <Breadcrumb />
     <div class="flex-between">
       <div class="detail_right">
-        <div class="padding16 bg_color_fff border_radius_10">
+        <div class="padding16 bg_color_fff border_radius_10 box_shadow_card">
           <div class="gap10">
             <div class="line_vertical"></div>
             <div class="font_size20 bold">课程笔记列表</div>
           </div>
-          <div class="flex-between mt10 course_List" 
-          :class="{'active': item === 1}"
-          v-for="item in 5" :key="item">
-            <img src="" alt="" style="width: 160px; height: 90px;" class="border_radius_8 bg_color_f5">
+          <div class="flex-between mt10 course_List cursor-pointer" 
+          @click="selectedItem = item"
+          :class="{'active': item.courseId === selectedItem.courseId}"
+          v-for="item in list" :key="item">
+            <img :src="item.coverImageUrl" alt="" style="width: 160px; height: 90px;" class="border_radius_8 bg_color_f5">
             <div class="flex_1 ml20">
-              <div class="font_size18 bold">课程笔记标题</div>
-              <div class="font_size14 line2 gray mt10">- 本文介绍两款开源的密码破解工具John the Ripp...</div>
+              <div class="font_size18 bold">{{ item.courseTitle }}</div>
+              <div class="font_size14 line2 gray mt10">{{ item.courseIntro }}</div>
             </div>
           </div>
         </div>
       </div>
-      <div class="flex_1 ml20 fit_content">
-        <noteList />
+      <div class="flex_1 ml20 fit_content bg_color_fff border_radius_10 padding16 box_shadow_card">
+        <Xuxibiji :info="selectedItem" />
       </div>
     </div>
   </div>
 </template>
 <script setup>
-
-import noteList from '@/pages/LearnNote/components/noteList.vue'
+import Xuxibiji from '@/pages/LearningSystem/components/xuxibiji.vue'
+import { getCourseList } from '@/api/course.js'
 
 
 import { ref, onMounted } from 'vue'
@@ -35,23 +36,29 @@ import { useRoute } from 'vue-router'
 import { useAppStore } from '@/pinia/appStore'
 const appStore = useAppStore()
 const route = useRoute()
-const query = route.query;
-const learnNoteId = ref(query.learnNoteId || '');
-const learnNoteDetail = ref({})
+const list = ref({})
+const selectedItem = ref({})
+
 onMounted(() => {
-  // getLearnNoteDetailFn();
+  getList();
 });
-const getLearnNoteDetailFn = async () => {
-   getLearnNoteDetail({learnNoteId: learnNoteId.value}).then(res => {
+const getList = async () => {
+   getCourseList({}).then(res => {
     if(res.code === 200){
       console.log(res)
-      learnNoteDetail.value = res.data || {};
+      list.value = res.rows || [];
+      if(list.value.length > 0){
+        selectedItem.value = list.value[0]
+      }
     }
   })
 };
 </script>
 <style lang="scss">
 .LearnNote{
+  .detail_right{
+    max-height: calc(100% - 100px);
+  }
   .course_List{
     padding: 16px;
     border-radius: 16px;

+ 0 - 101
src/pages/LearnNote/components/noteList.vue

@@ -1,101 +0,0 @@
-<template>
-  <div class="xuxibiji">
-    <div class="list_item padding16 border_radius_16 flex-center-between bg_color_fff mb20" 
-    v-for="(item, index) in 4" :key="index">
-      <div class="flex_1">
-        <div class="bold font_size18">这是笔记名称</div>
-        <div class="gray999 mt5">{{$t('common.genxinyu')}} 2025-11-08 03:26</div>
-      </div>
-      <div>
-        <el-button type="primary" plain size="large" @click="openAddDialog()">
-          <el-icon><EditPen /></el-icon>
-          <span class="ml10">{{$t('common.edit')}}</span>
-        </el-button>
-        <el-button type="danger" plain size="large" @click="del(index)">
-          <el-icon><Delete /></el-icon>
-          <span class="ml10">{{$t('common.delete')}}</span>
-        </el-button>
-      </div>
-    </div>
-    <Pagination 
-      :total="listTotal"
-      :page-size="searchFom.pageSize"
-      :current-page="searchFom.pageNum"
-      @page-change="handlePageChange"
-    />
-    <BlockNoteEditorDialog ref="blockNoteEditorDialogRef" />
-  </div>
-</template>
-<script setup>
-import { ElMessageBox } from 'element-plus'
-import addIcon from '@/assets/imgs/add.png'
-import BlockNoteEditorDialog from '@/components/BlockNoteEditorDialog.vue'
-import Pagination from '@/components/Pagination.vue'
-import { getCourseList } from '@/api/course.js'
-import { ref, onMounted,reactive } from 'vue'
-import { useAppStore } from '@/pinia/appStore'
-const appStore = useAppStore()
-defineProps({
-  info: {
-    type: Object,
-    default: () => ({})
-  }
-})
-const comments = ref('');
-const listTotal = ref(0);
-const searchFom = reactive({
-  pageNum: 1,
-  pageSize: 10,
-})
-const list = ref([]);
-
-onMounted(() => {
-  getList();
-});
-
-const handlePageChange = (page) => {
-  searchFom.pageNum = page
-  // 这里可以添加获取数据的逻辑
-  console.log('当前页:', page);
-  getList();
-}
-// 查询寻找工作流列表
-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 blockNoteEditorDialogRef = ref(null)
-const openAddDialog = () => {
-  blockNoteEditorDialogRef.value.openDialog();
-};
-// 删除笔记
-const del = (index) => {
-  // list.value.splice(index, 1)
-  ElMessageBox.confirm('确定删除吗?', '提示', {
-    confirmButtonText: '确定',
-    cancelButtonText: '取消',
-    type: 'warning'
-  }).then(() => {
-    getList();
-  }).catch(() => {
-    // 取消删除
-  });
-};
-</script>
-<style scoped lang="scss">
-.xuxibiji{
-  .addBtn{
-    cursor: pointer;
-    margin-top: 20px;
-    padding: 10px 20px;
-    color: #fff;
-  }
-}
-</style>

+ 1 - 1
src/pages/LearningSystem/LearningSystem.vue

@@ -105,7 +105,7 @@
       <!-- 分页 -->
       <!-- 替换原有的分页代码 -->
       <Pagination 
-        :total="searchFom.total"
+        :total="listTotal"
         :page-size="searchFom.pageSize"
         :current-page="searchFom.pageNum"
         @page-change="handlePageChange"

+ 1 - 1
src/pages/LearningSystem/components/xuxibiji.vue

@@ -4,7 +4,7 @@
       <div class="line_vertical"></div>
       <div class="font_size18 bold">{{$t('common.xuxibiji')}}</div>
     </div>
-    <div class="addBtn flex-center gradient border_radius_10" @click="openAddDialog">
+    <div class="addBtn flex-center gradient border_radius_10" @click="openAddDialog" v-if="info.courseId">
       <div class="gap10">
         <img :src="addIcon" alt="" style="width:30px;height:30px">
         <span class="font_size18">{{$t('common.add')}}{{$t('common.xuxibiji')}}</span>

+ 35 - 16
src/pages/mibiShop/mibiShop.vue

@@ -3,16 +3,28 @@
     <Breadcrumb />
     <div class="list">
       <div class="list_item bg_color_fff border_radius_16 box_shadow_card"
-      v-for="item in 10" :key="item"
+      v-for="item in list" :key="item"
       >
-        <img src="" alt="" style="width: 291.2px; height: 291.2px;" class="bg_color_f5">
+        <img :src="item.imageUrl" alt="" style="width: 291.2px; height: 291.2px;border-radius: 16px 16px 0 0;" class="bg_color_f5">
         <div class="item_info padding16">
           <div class="line2 font_size18 bold line_height24">
-            {{item==1?'小红xhs书虚拟电商赚钱项目开店选品定价上架自动发货在...':'小红xhs书虚拟'}}
+            {{item.itemName}}
           </div>
           <div class="flex-center-between">
-            <div class="bold color_price font_size20">900米币</div>
-            <div class="border_radius_4 lijiduihuan  color_fff gradient font_size14 flex-center mt10">
+            <div class="bold color_price font_size20">{{item.points}}{{$t('common.mibi')}}</div>
+            <div class="border_radius_4 lijiduihuan  color_fff gradient font_size14 flex-center mt10"
+             @click="confirmBuy({
+                callback:initList,
+                appStore,
+                router,
+                type:'pointsBalance',
+                price:item.points,
+                t,
+                productId:item.itemId,
+                orderType:'mi_mall',
+                payMethod:'MI'
+              })"
+            >
               立即兑换
             </div>
           </div>
@@ -30,12 +42,14 @@
 <script setup>
 import Pagination from '@/components/Pagination.vue'
 import { ref, onMounted,reactive } from 'vue'
-import { useRoute } from 'vue-router'
+import { useRouter } from 'vue-router'
 import { useAppStore } from '@/pinia/appStore'
+import { getMallList } from '@/api/mall.js'
+import { confirmBuy } from '@/utils/util.js'
+import { useI18n } from 'vue-i18n' 
+const { t } = useI18n() 
 const appStore = useAppStore()
-const route = useRoute()
-const query = route.query;
-const learnNoteId = ref(query.learnNoteId || '');
+const router = useRouter()
 
 
 // 添加分页相关数据
@@ -43,10 +57,10 @@ const list = ref([]);
 const listTotal = ref(0);
 const searchFom = reactive({
   pageNum: 1,
-  pageSize: 10,
+  pageSize: 20,
 })
 onMounted(() => {
-  // getList();
+  getList('init');
 });
 
 const handlePageChange = (page) => {
@@ -55,18 +69,23 @@ const handlePageChange = (page) => {
   console.log('当前页:', page);
   getList();
 }
+const initList = ()=>{
+  getList('init');
+};
 // 查询寻找工作流列表
 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 getMallList(searchFom)
+  if(res.code === 200){
+    listTotal.value = res.total || 0;
+    list.value = res.rows || [];
+  }
 };
 
+
+
 </script>
 <style lang="scss">
 .mibiShop{

+ 2 - 1
src/utils/util.js

@@ -48,7 +48,8 @@ export function formatDeadline(deadline) {
   const diffHours = Math.ceil(diffTime / (1000 * 60 * 60)) % 24;
   return {diffDays,diffHours};
 }
-export function confirmBuy({type='baoMiBalance',price=0,callback,appStore,router,t,payMethod,orderType,productId}){
+//type: pointsBalance  pointsBalance
+export function confirmBuy({type='pointsBalance',price=0,callback,appStore,router,t,payMethod,orderType,productId}){
   const balance = appStore.userInfo?.[type] || 0;
   if(balance < price ){
     ElMessageBox.confirm('您的余额不足,是否前往充值?', t('common.tip'), {