Selaa lähdekoodia

```
feat(auth): 添加登录验证功能并修复课程详情跳转逻辑

- 在App.vue中引入provide函数用于跨组件通信
- 添加openLoginDialog函数到全局提供者
- 在LearningSystem页面注入openLoginDialog并添加登录验证
- 新增isLogin工具函数用于判断用户登录状态
- 修复课程详情页购买判断逻辑,从固定false改为根据buyFlag判断
- 新增getChaptersList API用于获取章节列表
- 在课程目录组件中使用真实章节数据替代静态数据
- 监听courseId变化动态获取章节列表

fix(order): 订单确认页面添加金额验证

- 在payNowFn函数中添加支付金额验证,避免0元支付

style(layout): 调整容器宽度配置

- 将容器宽度从80%改为100%
- 调整最小宽度配置

refactor(utils): 优化工具函数错误处理

- 注释掉报名失败时的错误提示,避免重复显示
- 添加登录验证工具函数
```

zhangningning 1 kuukausi sitten
vanhempi
commit
b6b201acad

+ 6 - 1
src/App.vue

@@ -56,7 +56,7 @@
 <script setup>
 import { logout } from '@/api/auth.js'
 import LoginDialog from './components/LoginDialog.vue'
-import { computed,ref,onMounted } from 'vue'
+import { computed,ref,onMounted, provide } from 'vue'
 import LangSwitch from './components/LangSwitch.vue'
 import { ElConfigProvider, ElMessage } from 'element-plus'
 import { useRoute, useRouter } from 'vue-router'
@@ -69,6 +69,8 @@ $i18n.global.locale.value = langStore.currentLang
 // 动态更新页面标题
 langStore.updateDynamicTitle()
 
+
+
 const route = useRoute()
 const router = useRouter()
 
@@ -118,6 +120,9 @@ const handleLogout = () => {
     router.push('/')
   })
 };
+
+
+provide('openLoginDialog', openLoginDialog);
 </script>
 
 <style lang="scss">

+ 4 - 0
src/api/course.js

@@ -15,4 +15,8 @@ export function getCourseDetail(data = {}) {
 //技能标签  bus_skill_tag
 export function getDictType(data = {}) {
   return request.get('/system/dict/type')
+}
+// 查询章节列表
+export function getChaptersList(data = {}) {
+  return request.get('/chapter/chaptersList/'+data.id)
 }

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

@@ -126,11 +126,15 @@
   import { getCategoryListTree } from '@/api/category.js'
   import { getCourseList } from '@/api/course.js'
 
+  import { isLogin } from '@/utils/util.js'
+  import { useI18n } from 'vue-i18n' 
+  const { t } = useI18n() 
+
 
   import { useRouter, useRoute } from 'vue-router'
   const router = useRouter();
   const route = useRoute();
-  import { ref, computed, reactive, onMounted } from 'vue'
+  import { ref, computed, reactive, onMounted, inject } from 'vue'
   //获取参数
   const query = route.query
   const categoryId = ref(query.categoryId || '');
@@ -150,6 +154,8 @@
     carouselHeight.value = calculatedHeight + 'px'
   }
 
+  const openLoginDialog = inject('openLoginDialog')
+
 
 
   // 一级分类列表
@@ -194,6 +200,10 @@
   }
 
   const goDetail = (item) => {
+    //判断是否登录
+    if(!isLogin({callback: openLoginDialog,t})){
+      return;
+    }
     //增加参数名称
     router.push({
       path: `/learning-system/detail`,

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

@@ -117,7 +117,7 @@
   };
   const goDetail = (item) => {
     //如果未支付,跳转到支付页面
-    if(false ){
+    if(item.buyFlag == 0 ){
       confirmBuy({
         callback:getDetail,
         appStore,

+ 22 - 7
src/pages/LearningSystem/components/CourseDirectory.vue

@@ -6,31 +6,46 @@
     </div>
     <div class="flex-center-between font_size16 gray list_item" 
     :class="{'active': index === 0}"
-    v-for="(item, index) in 4" :key="index">
+    v-for="(item, index) in list" :key="index">
       <div class="gap10">
-        <div>第一节</div>
+        <div>{{item.chapterOrderName}}</div>
         <div class="gap5">
           <img :src="muluIcon" alt="" style="width:20px;height:20px" v-if="index === 0">
-          <span>行业要求与职业发展路线</span>
+          <span>{{item.chapterName}}</span>
         </div>
       </div>
-      <div>20:23</div>
+      <div>{{item.chapterTime}}</div>
     </div>
   </div>
 </template>
 <script setup>
 import muluIcon from '@/assets/imgs/mulu.png'
-import { getCourseList } from '@/api/course.js'
-import { ref, onMounted } from 'vue'
-defineProps({
+import { getChaptersList } from '@/api/course.js'
+import { ref, onMounted, watch } from 'vue'
+const props = defineProps({
   info: {
     type: Object,
     default: () => ({})
   }
 })
 
+//监听props.info.courseId变化
+watch(() => props.info.courseId, (newVal, oldVal) => {
+  if(newVal !== oldVal){
+    getChaptersListFn();
+  }
+})
+
 const list = ref([]);
 
+const getChaptersListFn = () => {
+   getChaptersList({id: props.info.courseId}).then(res => {
+    if(res.code === 200){
+      list.value = res.rows || [];
+    }
+  })
+};
+
 </script>
 <style scoped lang="scss">
   .kechengmulu{

+ 4 - 0
src/pages/order/orderConfirm.vue

@@ -258,6 +258,10 @@ const payNowFn = () => {
     DGTMessage.warning('请先同意协议')
     return
   }
+  if(payType.value == 1 && orderInfo.orderAmt <= 0){
+    DGTMessage.warning('请输入金额')
+    return
+  }
   loading.value = true;
   createOrder(orderInfo).then(res => {
     if(res.code === 200){

+ 3 - 2
src/styles/index.scss

@@ -67,8 +67,9 @@ body{
 // 容器宽度限制(统一页面最大宽度,居中显示)
 .container {
   max-width: 1528px;
-	width: 80%;
-	min-width: 1200px;
+	width: 100%;
+	// min-width: 1200px;
+	min-width: 1528px;
   margin: 0 auto;
   // padding: 20px;
 	padding: 0 4px;

+ 22 - 1
src/utils/util.js

@@ -25,7 +25,7 @@ export async function submitSignUp(formData,t,callback) {
       }
       return response.data;
     } else {
-      DGTMessage.error(response.msg || t('workflowTrade.signUpFailed'));
+      // DGTMessage.error(response.msg || t('workflowTrade.signUpFailed'));
       return null;
     }
   } catch (error) {
@@ -92,3 +92,24 @@ export function confirmBuy({type='baoMiBalance',price=0,callback,appStore,router
     });
   }
 }
+//判断是否登录
+export function isLogin({callback,t}){
+  let token = localStorage.getItem('token');
+  if(!token){
+    //确认弹框
+    ElMessageBox.confirm('您未登录,是否前往登录?', t('common.tip'), {
+      confirmButtonText: t('common.confirm'),
+      cancelButtonText: t('common.cancel'),
+      type: 'warning'
+    }).then(() => {
+      // 确认购买
+      if(callback && typeof callback === 'function'){
+        callback();
+      }
+    }).catch(() => {
+      // 取消购买
+    });
+    return false;
+  }
+  return true;
+}