Преглед изворни кода

云课堂管理后台代码

QuYueTing пре 1 месец
родитељ
комит
2f78430626
14 измењених фајлова са 10093 додато и 240 уклоњено
  1. 9701 61
      fhKeeper/formulahousekeeper/course-manager/courseManager.log
  2. 1 1
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/controller/CommonUploadController.java
  3. 2 1
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/controller/CourseTypeController.java
  4. 21 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/controller/SysUserController.java
  5. 11 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/entity/CourseInfo.java
  6. 46 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/entity/SysUser.java
  7. 16 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/mapper/SysUserMapper.java
  8. 16 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/service/SysUserService.java
  9. 20 0
      fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/service/impl/SysUserServiceImpl.java
  10. 3 3
      fhKeeper/formulahousekeeper/course-manager/src/main/resources/application-dev.yml
  11. 1 1
      fhKeeper/formulahousekeeper/course-manager/src/main/resources/application.yml
  12. 18 0
      fhKeeper/formulahousekeeper/course-manager/src/main/resources/mapper/SysUserMapper.xml
  13. 112 0
      fhKeeper/formulahousekeeper/course-pc/src/components/TinymceEditor.vue
  14. 125 173
      fhKeeper/formulahousekeeper/course-pc/src/views/coursemanagement/list.vue

Разлика између датотеке није приказан због своје велике величине
+ 9701 - 61
fhKeeper/formulahousekeeper/course-manager/courseManager.log


+ 1 - 1
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/controller/CommonUploadController.java

@@ -56,7 +56,7 @@ public class CommonUploadController {
             }
             inputStream.close();
             outputStream.close();
-            msg.data = serverName;
+            msg.data = "/upload/"+serverName;
         } catch (Exception exception) {
             exception.printStackTrace();
             log.error(exception.getMessage());

+ 2 - 1
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/controller/CourseTypeController.java

@@ -73,6 +73,7 @@ public class CourseTypeController {
             }
         }
         courseTypeService.saveOrUpdate(courseType);
+        httpRespMsg.data = courseType;
         return httpRespMsg;
 
     }
@@ -135,7 +136,7 @@ public class CourseTypeController {
             courseType.setId(id);
             courseType.setCoverImage("/upload/"+serverName);
             courseTypeService.saveOrUpdate(courseType);
-            msg.data = serverName;
+            msg.data = courseType.getCoverImage();
         } catch (Exception exception) {
             exception.printStackTrace();
         }

+ 21 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/controller/SysUserController.java

@@ -0,0 +1,21 @@
+package com.management.platform.controller;
+
+
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * <p>
+ *  前端控制器
+ * </p>
+ *
+ * @author Seyason
+ * @since 2025-04-16
+ */
+@RestController
+@RequestMapping("/sys-user")
+public class SysUserController {
+
+}
+

+ 11 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/entity/CourseInfo.java

@@ -7,9 +7,12 @@ import com.baomidou.mybatisplus.annotation.TableId;
 import java.time.LocalDateTime;
 import com.baomidou.mybatisplus.annotation.TableField;
 import java.io.Serializable;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.experimental.Accessors;
+import org.springframework.format.annotation.DateTimeFormat;
 
 /**
  * <p>
@@ -90,6 +93,8 @@ public class CourseInfo extends Model<CourseInfo> {
      * 上传日期
      */
     @TableField("create_date")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
     private LocalDateTime createDate;
 
     /**
@@ -116,6 +121,12 @@ public class CourseInfo extends Model<CourseInfo> {
     @TableField("course_url")
     private String courseUrl;
 
+    /**
+     * 课程分类名称
+     */
+    @TableField(exist = false)
+    private String courseTypeName;
+
 
     @Override
     protected Serializable pkVal() {

+ 46 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/entity/SysUser.java

@@ -0,0 +1,46 @@
+package com.management.platform.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import com.baomidou.mybatisplus.annotation.TableField;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author Seyason
+ * @since 2025-04-16
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class SysUser extends Model<SysUser> {
+
+    private static final long serialVersionUID=1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    @TableField("username")
+    private String username;
+
+    @TableField("pwd")
+    private String pwd;
+
+    @TableField("indate")
+    private LocalDateTime indate;
+
+
+    @Override
+    protected Serializable pkVal() {
+        return this.id;
+    }
+
+}

+ 16 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/mapper/SysUserMapper.java

@@ -0,0 +1,16 @@
+package com.management.platform.mapper;
+
+import com.management.platform.entity.SysUser;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ *  Mapper 接口
+ * </p>
+ *
+ * @author Seyason
+ * @since 2025-04-16
+ */
+public interface SysUserMapper extends BaseMapper<SysUser> {
+
+}

+ 16 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/service/SysUserService.java

@@ -0,0 +1,16 @@
+package com.management.platform.service;
+
+import com.management.platform.entity.SysUser;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ *  服务类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2025-04-16
+ */
+public interface SysUserService extends IService<SysUser> {
+
+}

+ 20 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/java/com/management/platform/service/impl/SysUserServiceImpl.java

@@ -0,0 +1,20 @@
+package com.management.platform.service.impl;
+
+import com.management.platform.entity.SysUser;
+import com.management.platform.mapper.SysUserMapper;
+import com.management.platform.service.SysUserService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ *  服务实现类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2025-04-16
+ */
+@Service
+public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {
+
+}

+ 3 - 3
fhKeeper/formulahousekeeper/course-manager/src/main/resources/application-dev.yml

@@ -1,5 +1,5 @@
 server:
-  port: 10018
+  port: 10031
   tomcat:
     uri-encoding: utf-8
     max-http-form-post-size: -1
@@ -13,7 +13,7 @@ spring:
       max-request-size: 100MB
   datasource:
     driver-class-name: com.mysql.cj.jdbc.Driver
-    url: jdbc:mysql://1.94.62.58:17089/man_dev?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&rewriteBatchedStatements=true&useSSL=false
+    url: jdbc:mysql://localhost:17089/course_manager?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&rewriteBatchedStatements=true&useSSL=false
     username: root
     password: P011430@Huoshi*
     hikari:
@@ -54,7 +54,7 @@ logging:
     #打印sql语句
     com.management.platform.mapper: error
   path: /log/
-  file: octopus.log
+  file: courseManager.log
 ##########
 mybatis-plus:
   #  mapper-locations: classpath:mapper/*/*.xml

+ 1 - 1
fhKeeper/formulahousekeeper/course-manager/src/main/resources/application.yml

@@ -95,7 +95,7 @@ referer:
     - localhost
     - ttkuaiban.com
     - ops.ttkuaiban.com
-    - 47.101.180.183
+    - 1.94.62.58
     - mldworktime.ttkuaiban.com
 excludeUrls: /wxcorp/*,/wxcorp/*/*,/dingding/*,/error,/testClient,/corpWXAuth,/wx-corp-info/*,/clean/*,/innerRoles/*,/operation-record/*
 syncDDMembUrl: http://worktime.ttkuaiban.com/api/dingding/syncCorpMembs

+ 18 - 0
fhKeeper/formulahousekeeper/course-manager/src/main/resources/mapper/SysUserMapper.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.management.platform.mapper.SysUserMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.management.platform.entity.SysUser">
+        <id column="id" property="id" />
+        <result column="username" property="username" />
+        <result column="pwd" property="pwd" />
+        <result column="indate" property="indate" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, username, pwd, indate
+    </sql>
+
+</mapper>

+ 112 - 0
fhKeeper/formulahousekeeper/course-pc/src/components/TinymceEditor.vue

@@ -0,0 +1,112 @@
+<template>
+  <div class="tinymce-editor">
+    <textarea :id="id" style="visibility:hidden;"></textarea>
+  </div>
+</template>
+
+<script>
+// Use self-hosted TinyMCE
+const loadTinyMCE = () => {
+  if (window.tinymce) return Promise.resolve(window.tinymce)
+  
+  return new Promise((resolve, reject) => {
+    const script = document.createElement('script')
+    script.src = '/static/tinymce/tinymce.min.js'
+    script.onload = () => {
+      if (window.tinymce) {
+        resolve(window.tinymce)
+      } else {
+        reject(new Error('Failed to load TinyMCE'))
+      }
+    }
+    script.onerror = reject
+    document.head.appendChild(script)
+  })
+}
+
+export default {
+  name: 'TinymceEditor',
+  props: {
+    value: {
+      type: String,
+      default: ''
+    },
+    init: {
+      type: Object,
+      default: () => ({})
+    },
+    placeholder: {
+      type: String,
+      default: ''
+    }
+  },
+  data() {
+    return {
+      id: 'tinymce-' + Date.now() + Math.floor(Math.random() * 1000),
+      editor: null,
+      hasChange: false
+    }
+  },
+  watch: {
+    value(val) {
+      if (!this.hasChange && this.editor) {
+        this.editor.setContent(val)
+      }
+    }
+  },
+  mounted() {
+    this.initEditor()
+  },
+  beforeDestroy() {
+    if (this.editor) {
+      this.editor.destroy()
+    }
+  },
+  methods: {
+    async initEditor() {
+      try {
+        const tinymce = await loadTinyMCE()
+        
+        const config = {
+          selector: `#${this.id}`,
+          language_url: this.init.language_url || '/static/tinymce/zh_CN.js',
+          language: this.init.language || 'zh_CN',
+          height: this.init.height || 300,
+          plugins: this.init.plugins || 'link lists image code table wordcount',
+          toolbar: this.init.toolbar || 'undo redo | formatselect | bold italic | alignleft aligncenter alignright | bullist numlist outdent indent | link image | code',
+          images_upload_handler: this.init.images_upload_handler || null,
+          placeholder: this.placeholder,
+          skin_url: '/static/tinymce/skins/ui/oxide',
+          content_css: '/static/tinymce/skins/content/default/content.css',
+          setup: editor => {
+            editor.on('init', () => {
+              editor.setContent(this.value)
+            })
+            editor.on('change keyup', () => {
+              this.hasChange = true
+              this.$emit('input', editor.getContent())
+            })
+          }
+        }
+
+        tinymce.init(config).then(editors => {
+          this.editor = editors[0]
+        }).catch(error => {
+          console.error('TinyMCE init error:', error)
+          this.$message.error('富文本编辑器初始化失败')
+        })
+      } catch (error) {
+        console.error('Failed to load TinyMCE:', error)
+        this.$message.error('加载富文本编辑器失败')
+      }
+    }
+  }
+}
+</script>
+
+<style>
+.tox-tinymce {
+  border-radius: 4px;
+  border: 1px solid #dcdfe6 !important;
+}
+</style>

+ 125 - 173
fhKeeper/formulahousekeeper/course-pc/src/views/coursemanagement/list.vue

@@ -4,29 +4,35 @@
         <el-col :span="24" class="toolbar" style="padding-bottom: 0px;">
             <el-form :inline="true" @submit.native.prevent>
                 <el-form-item label="课程分类">
-                    <el-select v-model="categoryValue" placeholder="请选择" clearable @change="searchList">
+                    <el-select v-model="categoryValue" placeholder="请选择" clearable @change="searchList" size="small">
                         <el-option v-for="item in categoryOptions" :key="item.value" :label="item.label" :value="item.value">
                         </el-option>
                     </el-select>
                 </el-form-item>
                 <el-form-item label="课程名称">
-                    <el-input v-model="keyword" placeholder="请输入" clearable @change="searchList"></el-input>
+                    <el-input v-model="keyword" placeholder="请输入" clearable @change="searchList" size="small"></el-input>
                 </el-form-item>
                 <el-form-item label="讲师">
-                    <el-input v-model="instructor" placeholder="请输入" clearable @change="searchList"></el-input>
+                    <el-input v-model="instructor" placeholder="请输入" clearable @change="searchList" size="small"></el-input>
                 </el-form-item>
                 <el-form-item>
-                    <el-button type="primary" @click="addCourse">添加课程</el-button>
+                    <el-button type="primary" @click="addCourse" size="small" >添加课程</el-button>
                 </el-form-item>
                 <el-form-item>
-                    <el-button type="primary" @click="batchManage">分类管理</el-button>
+                    <el-button type="primary" @click="batchManage" size="small">分类管理</el-button>
                 </el-form-item>
             </el-form>
         </el-col>
 
         <!--列表-->
-        <el-table :data="list" highlight-current-row v-loading="listLoading" :height="tableHeight" style="width: 100%;">
+            <el-table :data="list" highlight-current-row v-loading="listLoading" :height="tableHeight" style="width: 100%;">
             <el-table-column type="index" width="50" align="center" label="#"></el-table-column>
+            <el-table-column label="封面" width="120" align="center">
+                <template slot-scope="scope">
+                    <img v-if="scope.row.coverImage" :src="scope.row.coverImage" class="course-cover-image" />
+                    <span v-else>无封面</span>
+                </template>
+            </el-table-column>
             <el-table-column prop="courseTypeName" label="课程分类" min-width="120" align="center"></el-table-column>
             <el-table-column prop="courseName" label="课程名称" min-width="180" align="center"></el-table-column>
             <el-table-column prop="courseInstructor" label="讲师" min-width="120" align="center"></el-table-column>
@@ -45,17 +51,12 @@
                     <span>{{ scope.row.courseUrl ? '1个' : '0个' }}</span>
                 </template>
             </el-table-column>
-            <el-table-column label="附件" min-width="100" align="center">
-                <template slot-scope="scope">
-                    <span>{{ scope.row.attachmentUrl ? '1个' : '0个' }}</span>
-                </template>
-            </el-table-column>
             
-            <el-table-column label="操作" width="200" class-name="btns" header-align="center" fixed="right">
+            <el-table-column label="操作" width="250" class-name="btns" header-align="center" fixed="right">
                 <template slot-scope="scope">
-                    <el-button size="mini" type="danger" @click="deleteItem(scope.row)">删除</el-button>
-                    <el-button size="mini" type="primary" @click="editItem(scope.row)">编辑</el-button>
-                    <el-button size="mini" :type="scope.row.courseStatus === 1 ? 'warning' : 'success'" @click="uploadItem(scope.row)">{{scope.row.courseStatus === 1 ? '下架' : '上架'}}</el-button>
+                    <el-button size="small" type="danger" @click="deleteItem(scope.row)">删除</el-button>
+                    <el-button size="small" type="primary" @click="editItem(scope.row)">编辑</el-button>
+                    <el-button size="small" :type="scope.row.courseStatus === 1 ? 'warning' : 'success'" @click="uploadItem(scope.row)">{{scope.row.courseStatus === 1 ? '下架' : '上架'}}</el-button>
                 </template>
             </el-table-column>
         </el-table>
@@ -85,59 +86,20 @@
                     <el-input v-model="newCourse.courseName" placeholder="请输入"></el-input>
                 </el-form-item>
                 <el-form-item label="课程介绍" prop="courseDesc">
-                    <div class="editor-container">
-                        <div class="editor-toolbar">
-                            <button type="button" class="editor-btn"><i class="el-icon-bold"></i></button>
-                            <button type="button" class="editor-btn"><i class="el-icon-italic"></i></button>
-                            <button type="button" class="editor-btn"><i class="el-icon-underline"></i></button>
-                            <button type="button" class="editor-btn"><i class="el-icon-strikethrough"></i></button>
-                            <span class="editor-separator"></span>
-                            <button type="button" class="editor-btn"><i class="el-icon-h1"></i></button>
-                            <button type="button" class="editor-btn"><i class="el-icon-h2"></i></button>
-                            <span class="editor-separator"></span>
-                            <select class="editor-select">
-                                <option>14px</option>
-                            </select>
-                            <span class="editor-separator"></span>
-                            <button type="button" class="editor-btn">文本</button>
-                            <span class="editor-separator"></span>
-                            <button type="button" class="editor-btn"><i class="el-icon-s-unfold"></i></button>
-                            <button type="button" class="editor-btn"><i class="el-icon-menu"></i></button>
-                            <button type="button" class="editor-btn"><i class="el-icon-s-operation"></i></button>
-                            <span class="editor-separator"></span>
-                            <button type="button" class="editor-btn"><i class="el-icon-picture-outline"></i></button>
-                        </div>
-                        <textarea v-model="newCourse.courseDesc" class="editor-content" placeholder="请输入文本"></textarea>
-                    </div>
-                </el-form-item>
-                <el-form-item label="讲师" prop="instructor">
-                    <el-input v-model="newCourse.instructor" placeholder="请输入"></el-input>
+                    <el-input
+                        v-model="newCourse.courseDesc"
+                        type="textarea"
+                        :rows="5"
+                        placeholder="请输入课程介绍"
+                    />
                 </el-form-item>
                 <el-form-item label="讲师介绍" prop="instructorDesc">
-                    <div class="editor-container">
-                        <div class="editor-toolbar">
-                            <button type="button" class="editor-btn"><i class="el-icon-bold"></i></button>
-                            <button type="button" class="editor-btn"><i class="el-icon-italic"></i></button>
-                            <button type="button" class="editor-btn"><i class="el-icon-underline"></i></button>
-                            <button type="button" class="editor-btn"><i class="el-icon-strikethrough"></i></button>
-                            <span class="editor-separator"></span>
-                            <button type="button" class="editor-btn"><i class="el-icon-h1"></i></button>
-                            <button type="button" class="editor-btn"><i class="el-icon-h2"></i></button>
-                            <span class="editor-separator"></span>
-                            <select class="editor-select">
-                                <option>14px</option>
-                            </select>
-                            <span class="editor-separator"></span>
-                            <button type="button" class="editor-btn">文本</button>
-                            <span class="editor-separator"></span>
-                            <button type="button" class="editor-btn"><i class="el-icon-s-unfold"></i></button>
-                            <button type="button" class="editor-btn"><i class="el-icon-menu"></i></button>
-                            <button type="button" class="editor-btn"><i class="el-icon-s-operation"></i></button>
-                            <span class="editor-separator"></span>
-                            <button type="button" class="editor-btn"><i class="el-icon-picture-outline"></i></button>
-                        </div>
-                        <textarea v-model="newCourse.instructorDesc" class="editor-content" placeholder="请输入文本"></textarea>
-                    </div>
+                    <el-input
+                        v-model="newCourse.instructorDesc"
+                        type="textarea"
+                        :rows="5"
+                        placeholder="请输入讲师介绍"
+                    />
                 </el-form-item>
                 <el-form-item label="课程价格" prop="price">
                     <el-input v-model="newCourse.price" placeholder="请输入"></el-input>
@@ -145,19 +107,20 @@
                 <el-form-item label="课程时间" prop="duration">
                     <el-input v-model="newCourse.duration" placeholder="请输入"></el-input>
                 </el-form-item>
-                <el-form-item label="相关文件">
+                <el-form-item label="课程封面">
                     <el-upload
+                        class="cover-uploader"
                         action="#"
+                        :show-file-list="false"
+                        :on-change="handleCoverImageChange"
                         :auto-upload="false"
-                        multiple
-                        list-type="text"
-                        :file-list="attachmentFiles"
-                        :on-change="handleAttachmentChange">
-                        <el-button size="small" type="primary">点击上传</el-button>
-                        <div slot="tip" class="el-upload__tip">可上传pdf/doc/ppt等文件</div>
+                        :before-upload="beforeImageUpload">
+                        <img v-if="newCourse.coverImageUrl" :src="newCourse.coverImageUrl" class="cover-image" />
+                        <i v-else class="el-icon-plus cover-uploader-icon"></i>
                     </el-upload>
+                    <div class="upload-tip">请上传课程封面图片,建议尺寸 16:9</div>
                 </el-form-item>
-                <el-form-item label="讲师照片">
+                <el-form-item label="讲师照片" prop="instructorImg">
                     <el-upload
                         class="instructor-uploader"
                         action="#"
@@ -165,7 +128,7 @@
                         :on-change="handleInstructorImageChange"
                         :auto-upload="false"
                         :before-upload="beforeImageUpload">
-                        <img v-if="instructorImageUrl" :src="instructorImageUrl" class="instructor-image" />
+                        <img v-if="newCourse.instructorImageUrl" :src="newCourse.instructorImageUrl" class="instructor-image" />
                         <i v-else class="el-icon-plus instructor-uploader-icon"></i>
                     </el-upload>
                     <div class="upload-tip">请上传讲师照片,建议尺寸 1:1</div>
@@ -175,7 +138,7 @@
                         action="#"
                         :auto-upload="false"
                         list-type="text"
-                        :file-list="videoFiles"
+                        :file-list="newCourse.videoFiles"
                         :on-change="handleVideoChange">
                         <el-button size="small" type="primary">点击上传</el-button>
                         <div slot="tip" class="el-upload__tip">只能上传mp4/avi文件</div>
@@ -187,61 +150,6 @@
                 <el-button type="primary" @click="submitNewCourse('newCourseForm')">{{newCourse.id ? '保存' : '添加'}}</el-button>
             </span>
         </el-dialog>
-        
-        <!-- 编辑课程 -->
-        <el-dialog :visible.sync="editDialogVisible" title="编辑课程" width="600px">
-            <el-form :model="currentCourse" ref="editCourseForm" label-width="100px" :rules="courseRules" v-if="currentCourse">
-                <el-form-item label="课程分类" prop="category">
-                    <el-select v-model="currentCourse.categoryValue" placeholder="请选择" style="width: 100%">
-                        <el-option v-for="item in categoryOptions" :key="item.value" :label="item.label" :value="item.value">
-                        </el-option>
-                    </el-select>
-                </el-form-item>
-                <el-form-item label="课程名称" prop="courseName">
-                    <el-input v-model="currentCourse.courseName"></el-input>
-                </el-form-item>
-                <el-form-item label="讲师" prop="instructor">
-                    <el-input v-model="currentCourse.instructor"></el-input>
-                </el-form-item>
-                <el-form-item label="价格" prop="price">
-                    <el-input v-model="currentCourse.price" placeholder="例如: ¥299">
-                        <template slot="prepend">¥</template>
-                    </el-input>
-                </el-form-item>
-                <el-form-item label="课程时间" prop="duration">
-                    <el-input v-model="currentCourse.duration" placeholder="例如: 2小时"></el-input>
-                </el-form-item>
-                <el-form-item label="视频">
-                    <el-upload
-                        action="#"
-                        :auto-upload="false"
-                        multiple
-                        list-type="text"
-                        :file-list="videoFiles"
-                        :on-change="handleVideoChange">
-                        <el-button size="small" type="primary">点击上传</el-button>
-                        <div slot="tip" class="el-upload__tip">只能上传mp4/avi文件</div>
-                    </el-upload>
-                </el-form-item>
-                <el-form-item label="附件">
-                    <el-upload
-                        action="#"
-                        :auto-upload="false"
-                        multiple
-                        list-type="text"
-                        :file-list="attachmentFiles"
-                        :on-change="handleAttachmentChange">
-                        <el-button size="small" type="primary">点击上传</el-button>
-                        <div slot="tip" class="el-upload__tip">可上传pdf/doc/ppt等文件</div>
-                    </el-upload>
-                </el-form-item>
-            </el-form>
-            <span slot="footer" class="dialog-footer">
-                <el-button @click="editDialogVisible = false">取 消</el-button>
-                <el-button type="primary" @click="updateCourse('editCourseForm')">确 定</el-button>
-            </span>
-        </el-dialog>
-        
         <!-- 分类管理 -->
         <el-dialog :visible.sync="categoryManageVisible" title="分类管理" width="600px">
             <el-table :data="categoryList" style="width: 100%" max-height="400">
@@ -324,6 +232,7 @@
 </template>
 <script>
 import App from '../../App.vue';
+    
     export default {
   components: { App },
         data() {
@@ -360,15 +269,17 @@ import App from '../../App.vue';
                     instructorDesc: '',
                     price: '',
                     duration: '',
+                    coverImage: '',
                     instructorImg: '',
-                    attachmentUrl: '',
-                    courseUrl: ''
+                    courseUrl: '',
+                    // 图片和文件上传
+                    coverImageUrl: '',
+                    coverImageFile: null,
+                    instructorImageUrl: '',
+                    instructorImageFile: null,
+                    videoFiles: []
                 },
                 
-                // 讲师照片上传
-                instructorImageUrl: '',
-                instructorImageFile: null,
-                
                 // 表单验证规则
                 courseRules: {
                     categoryValue: [
@@ -400,7 +311,6 @@ import App from '../../App.vue';
                 
                 // 文件上传
                 videoFiles: [],
-                attachmentFiles: [],
                 
                 // 分类管理
                 categoryList: [],
@@ -477,6 +387,24 @@ import App from '../../App.vue';
             addCourse() {
                 this.addDialogVisible = true;
                 // 这里可以初始化新课程数据
+                this.newCourse = {
+                    categoryValue: '',
+                    courseName: '',
+                    courseDesc: '',
+                    instructor: '',
+                    instructorDesc: '',
+                    price: '',
+                    duration: '',
+                    coverImage: '',
+                    instructorImg: '',
+                    courseUrl: '',
+                    // 图片和文件上传
+                    coverImageUrl: '',
+                    coverImageFile: null,
+                    instructorImageUrl: '',
+                    instructorImageFile: null,
+                    videoFiles: []
+                }
             },
             
             // 分类管理
@@ -570,20 +498,15 @@ import App from '../../App.vue';
                             price: courseDetail.coursePrice,
                             duration: courseDetail.courseDuration || '',
                             instructorImg: courseDetail.instructorImg || '',
-                            attachmentUrl: courseDetail.attachmentUrl || '',
+                            coverImage: courseDetail.coverImage || '',
                             courseUrl: courseDetail.courseUrl || ''
                         };
                         
-                        // 设置讲师照片URL(如果有)
-                        this.instructorImageUrl = courseDetail.instructorImg ? courseDetail.instructorImg : '';
-                        
-                        // 设置附件和视频文件列表
-                        this.attachmentFiles = courseDetail.attachmentUrl ? [{
-                            name: '已上传附件',
-                            url: courseDetail.attachmentUrl
-                        }] : [];
+                        // 设置课程封面和讲师照片URL(如果有)
+                        this.newCourse.coverImageUrl = courseDetail.coverImage ? courseDetail.coverImage : '';
+                        this.newCourse.instructorImageUrl = courseDetail.instructorImg ? courseDetail.instructorImg : '';
                         
-                        this.videoFiles = courseDetail.courseUrl ? [{
+                        this.newCourse.videoFiles = courseDetail.courseUrl ? [{
                             name: '已上传视频',
                             url: courseDetail.courseUrl
                         }] : [];
@@ -662,7 +585,7 @@ import App from '../../App.vue';
             
             // 处理视频文件上传
             handleVideoChange(file, fileList) {
-                this.videoFiles = fileList;
+                this.newCourse.videoFiles = fileList;
                 // 立即上传视频文件
                 if (file && file.raw) {
                     this.listLoading = true;
@@ -727,14 +650,34 @@ import App from '../../App.vue';
                 return isImage && isLt2M;
             },
             
+            // 处理课程封面变更
+            handleCoverImageChange(file) {
+                this.newCourse.coverImageFile = file.raw;
+                if (this.newCourse.coverImageFile) {
+                    this.newCourse.coverImageUrl = URL.createObjectURL(this.newCourse.coverImageFile);
+                    // 立即上传课程封面
+                    this.listLoading = true;
+                    this.uploadFile(this.newCourse.coverImageFile, fileName => {
+                        this.listLoading = false;
+                        if (fileName) {
+                            this.newCourse.coverImage = fileName;
+                            this.$message({
+                                type: 'success',
+                                message: '课程封面上传成功!'
+                            });
+                        }
+                    });
+                }
+            },
+
             // 处理讲师照片变更
             handleInstructorImageChange(file) {
-                this.instructorImageFile = file.raw;
-                if (this.instructorImageFile) {
-                    this.instructorImageUrl = URL.createObjectURL(this.instructorImageFile);
+                this.newCourse.instructorImageFile = file.raw;
+                if (this.newCourse.instructorImageFile) {
+                    this.newCourse.instructorImageUrl = URL.createObjectURL(this.newCourse.instructorImageFile);
                     // 立即上传讲师照片
                     this.listLoading = true;
-                    this.uploadFile(this.instructorImageFile, fileName => {
+                    this.uploadFile(this.newCourse.instructorImageFile, fileName => {
                         this.listLoading = false;
                         if (fileName) {
                             this.newCourse.instructorImg = fileName;
@@ -788,19 +731,19 @@ import App from '../../App.vue';
                             option => option.value === this.newCourse.categoryValue
                         );
                         
-                        // 准备API请求参数
-                        const params = {
-                            courseTypeId: this.newCourse.categoryValue,
-                            courseName: this.newCourse.courseName,
-                            courseDesc: this.newCourse.courseDesc,
-                            courseInstructor: this.newCourse.instructor,
-                            instructorDesc: this.newCourse.instructorDesc,
-                            coursePrice: this.newCourse.price,
-                            instructorImg: this.newCourse.instructorImg,
-                            attachmentUrl: this.newCourse.attachmentUrl,
-                            courseUrl: this.newCourse.courseUrl,
-                            courseDuration: this.newCourse.duration
-                        };
+                // 准备API请求参数
+                const params = {
+                    courseTypeId: this.newCourse.categoryValue,
+                    courseName: this.newCourse.courseName,
+                    courseDesc: this.newCourse.courseDesc,
+                    courseInstructor: this.newCourse.instructor,
+                    instructorDesc: this.newCourse.instructorDesc,
+                    coursePrice: this.newCourse.price,
+                    instructorImg: this.newCourse.instructorImg,
+                    coverImage: this.newCourse.coverImage,
+                    courseUrl: this.newCourse.courseUrl,
+                    courseDuration: this.newCourse.duration
+                };
                         
                         // 如果是编辑模式,添加课程ID
                         if (this.newCourse.id) {
@@ -823,14 +766,16 @@ import App from '../../App.vue';
                                     instructorDesc: '',
                                     price: '',
                                     duration: '',
+                                    coverImage: '',
                                     instructorImg: '',
-                                    attachmentUrl: '',
-                                    courseUrl: ''
+                                    courseUrl: '',
+                                    // 图片和文件上传
+                                    coverImageUrl: '',
+                                    coverImageFile: null,
+                                    instructorImageUrl: '',
+                                    instructorImageFile: null,
+                                    videoFiles: []
                                 };
-                                this.videoFiles = [];
-                                this.attachmentFiles = [];
-                                this.instructorImageUrl = '';
-                                this.instructorImageFile = null;
                                 
                                 this.addDialogVisible = false;
                                 
@@ -1046,7 +991,7 @@ import App from '../../App.vue';
                         // 创建FormData对象用于上传文件
                         const formData = new FormData();
                         formData.append('id', categoryId);
-                        formData.append('coverImg', this.coverImageFile);
+                        formData.append('coverImage', this.coverImageFile);
                         
                         // 调用上传图片的API
                         this.http.uploadFile('/course-type/uploadCover', formData, res => {
@@ -1828,6 +1773,13 @@ import App from '../../App.vue';
 }
 </style>
 <style>
+.course-cover-image {
+    width: 100px;
+    height: 100px;
+    object-fit: cover;
+    border-radius: 4px;
+}
+
 .otherForm .el-form-item{
     float: left;
     width: 50%;