bzkf3 2 年之前
父节点
当前提交
2c5a691072

+ 1 - 0
package.json

@@ -19,6 +19,7 @@
     "swiper": "5.2.0",
     "tinymce": "^6.3.0",
     "vue": "^3.2.45",
+    "vue-cropper": "^1.0.5",
     "vue-router": "^4.1.6"
   },
   "devDependencies": {

+ 6 - 0
pnpm-lock.yaml

@@ -20,6 +20,7 @@ specifiers:
   vite: ^3.2.4
   vite-plugin-windicss: ^1.8.8
   vue: ^3.2.45
+  vue-cropper: ^1.0.5
   vue-router: ^4.1.6
   windicss: ^3.5.6
 
@@ -34,6 +35,7 @@ dependencies:
   swiper: 5.2.0
   tinymce: 6.3.0
   vue: 3.2.45
+  vue-cropper: 1.0.5
   vue-router: 4.1.6_vue@3.2.45
 
 devDependencies:
@@ -1368,6 +1370,10 @@ packages:
       fsevents: 2.3.2
     dev: true
 
+  /vue-cropper/1.0.5:
+    resolution: {integrity: sha512-D4XXdqWmMWRLOIV9LIh7/mkH6OBOMQDFbRjwntkxmAtxOtwpC9U5ZZ6lSXw5F5cbd4g8znDjk6MuCwIL+fZSrA==}
+    dev: false
+
   /vue-demi/0.13.11_vue@3.2.45:
     resolution: {integrity: sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==}
     engines: {node: '>=12'}

+ 25 - 5
src/pages/personal/components/Homework/ssys/xszy/up.vue

@@ -1,6 +1,7 @@
 <script setup>
 import { ElMessage } from 'element-plus';
-
+import { VueCropper } from 'vue-cropper'
+import 'vue-cropper/dist/index.css'
 const props = defineProps({
   pid: String
 })
@@ -25,9 +26,24 @@ const rules = {
 
 let isRead = $ref(false)
 let formRef = $ref()
-function handleSubmit() {
+async function handleSubmit() {
   // console.log('form :>> ', form);
   if (isRead) {
+    await Promise.all(CropperFileRefs.map(async CropperFileRef => {
+      CropperFileRef.getCropBlob(cropBlob => {
+            const cropFile = new File([cropBlob], 'crop.jpeg', { type: cropBlob.type })
+            console.log('cropFile :>> ', cropFile);
+            upload_file(cropFile).then(res => {
+              if (res.code == 1) {
+                this.formline.ks_img_cropping = res.data.url;
+                resolve(res.data.url)
+              } else {
+                reject(null)
+              }
+            })
+          })
+    }))
+
     formRef.validate().then((res) => {
       console.log('res :>> ', res);
       if (res === true) {
@@ -62,6 +78,7 @@ function handleBack() {
 }
 
 let filelist = $ref([])
+let CropperFileRefs = $ref([])
 
 function handleUploadFinished(list) {
   console.log('$filelist :>> ', list);
@@ -70,7 +87,8 @@ function handleUploadFinished(list) {
     return {
       name: d.file_name,
       file: d.url,
-      keyword: d.file_name?.substr(0, d.file_name?.lastIndexOf('.')) ?? ''
+      keyword: d.file_name?.substr(0, d.file_name?.lastIndexOf('.')) ?? '',
+      blob: URL.createObjectURL(item.raw)
     }
   })
 }
@@ -122,10 +140,12 @@ function handleUploadFinished(list) {
 
         <div class="w-full grid grid-cols-3 gap-4">
           <template v-if="filelist.length">
-            <div class="flex_center" v-for="i in filelist">
+            <div class="flex_center" v-for="(i, idx) in filelist">
               <div class="rounded-xl shadow bg-white flex flex-col overflow-hidden cursor-pointer" :key="i">
                 <div class="w-full flex-none h-160px">
-                  <img :src="getFullUrl(i.file)" alt="" class="w-full h-full" />
+                  <!-- <img :src="getFullUrl(i.file)" alt="" class="w-full h-full" /> -->
+                  <VueCropper ref="cropper" autoCrop :img="(i.blob)" fixed centerBox :ref="CropperFileRefs[idx]">
+                  </VueCropper>
                 </div>
                 <div class="p-2 flex justify-between items-center flex-auto">
                   <el-input v-model="i.keyword" placeholder="请输入作业名称"></el-input>

+ 119 - 27
src/pages/personal/components/MyCourse/ssys-create.vue

@@ -4,31 +4,42 @@
     <el-card>
       <div style="padding: 0 75px;">
         <span class="title">全景课堂</span>
-        <span class="subTitle">我的课程 - 我创建的 - <span class="pointer" @click="goBack">全景课堂</span> - <span style="color: #000;">{{editId=="" ? "创建" : "编辑"}}课程</span></span>
+        <span class="subTitle">我的课程 - 我创建的 - <span class="pointer" @click="goBack">全景课堂</span> - <span
+            style="color: #000;">{{ editId== "" ? "创建" : "编辑"}}课程</span></span>
       </div>
     </el-card>
 
     <el-card>
-      <div style="color: #050026;font-size: 18px;font-weight: 400;">{{editId=="" ? "创建" : "编辑"}}课程</div>
+      <div style="color: #050026;font-size: 18px;font-weight: 400;">{{ editId== "" ? "创建" : "编辑"}}课程</div>
       <div class="formContent">
-        <el-form :model="formline" ref="formline" :rules="rules" size="large" label-position="top" class="demo-ruleForm">
+        <el-form :model="formline" ref="formline" :rules="rules" size="large" label-position="top"
+          class="demo-ruleForm">
           <div class="must">
             <div class="label">课程封面图</div>
             <div class="uploadDiv">
               <div style="display: flex;">
-                <el-upload class="mainUpload" action="" accept=".png, .jpg, .jpeg" :auto-upload="false" list-type="picture-card" :on-change="handleMainChange" :file-list="fileList">
-                  <el-icon size="38" color="#9d9ab9" v-if="fileList.length==0">
+                <el-upload class="mainUpload" action="" accept=".png, .jpg, .jpeg" :auto-upload="false"
+                  list-type="picture-card" :on-change="handleMainChange" :file-list="fileList">
+                  <el-icon size="38" color="#9d9ab9" v-if="fileList.length == 0">
                     <Picture />
                   </el-icon>
                   <img v-else :src="fileList[0].url" alt="" style="width: 100%;height: 100%;" />
                 </el-upload>
                 <div style="font-size: 12px;margin-left: 20px;position: relative;">
                   <div style="color: #949494;">支持格式:jpg,png,jpeg(200kb以内) 建议尺寸600x320</div>
-                  <div style="color: #F35421;position: absolute;bottom: 0;" v-if="fileList.length==0">{{mainTip}}</div>
+                  <div style="color: #F35421;position: absolute;bottom: 0;" v-if="fileList.length == 0">{{ mainTip }}
+                  </div>
                 </div>
               </div>
             </div>
           </div>
+          <el-form-item label="封面缩略图" prop="ks_img_cropping">
+            <div class="w-300px h-160px">
+              <VueCropper ref="cropper" autoCrop :img="fileList[0]?.url" fixed centerBox>
+              </VueCropper>
+            </div>
+
+          </el-form-item>
           <el-form-item label="课程名称" prop="ks_name">
             <el-input v-model="formline.ks_name" />
           </el-form-item>
@@ -51,26 +62,30 @@
             </el-form-item>
           </div> -->
           <el-form-item label="开始时间 - 结束时间" prop="ks_start_datetime">
-            <el-date-picker v-model="time" type="datetimerange" @change="handleTimeChange" value-format="YYYY-MM-DD HH:mm:ss" />
+            <el-date-picker v-model="time" type="datetimerange" @change="handleTimeChange"
+              value-format="YYYY-MM-DD HH:mm:ss" />
           </el-form-item>
           <div class="must" style="display: block;">
             <div class="label" style="margin-bottom: 12px;">类型(每个类型只能选一个)</div>
             <div class="showType">
-              <div class="typeItem" style="background: #00a3ff;">{{formline.grade_name}}</div>
-              <div class="typeItem" style="background: rgba(0,131,197,0.8);">{{formline.subject_name}}</div>
+              <div class="typeItem" style="background: #00a3ff;">{{ formline.grade_name }}</div>
+              <div class="typeItem" style="background: rgba(0,131,197,0.8);">{{ formline.subject_name }}</div>
             </div>
           </div>
           <div class="type">
             <div class="flex">
               <div class="label">年级</div>
               <div class="valueDiv">
-                <div class="item pointer" :class="formline.grade_id==item.grade_id?'active':''" @click="initGrade(item)" v-for="item in gradeData" :key="item.grade_id">{{item.grade_name}}</div>
+                <div class="item pointer" :class="formline.grade_id == item.grade_id ? 'active' : ''"
+                  @click="initGrade(item)" v-for="item in gradeData" :key="item.grade_id">{{ item.grade_name }}</div>
               </div>
             </div>
             <div class="flex">
               <div class="label">分类</div>
               <div class="valueDiv">
-                <div class="item pointer" :class="formline.subject_id==item.subject_id?'active':''" @click="initSubject(item)" v-for="item in subjectData" :key="item.subject_id">{{item.subject_name}}</div>
+                <div class="item pointer" :class="formline.subject_id == item.subject_id ? 'active' : ''"
+                  @click="initSubject(item)" v-for="item in subjectData" :key="item.subject_id">{{ item.subject_name }}
+                </div>
               </div>
             </div>
           </div>
@@ -91,9 +106,11 @@
             </div>
           </div> -->
           <el-form-item label="附件" prop="ks_kj">
-            <file-upload-progress v-model:part="formline.ks_kj" :limit="1" accept=".doc,.docx,.xls,.xlsx,.ppt,.pptx,.pdf,.mp4,.mp3" :size-limit="500*1024">
+            <file-upload-progress v-model:part="formline.ks_kj" :limit="1"
+              accept=".doc,.docx,.xls,.xlsx,.ppt,.pptx,.pdf,.mp4,.mp3" :size-limit="500 * 1024">
               <template #default>
-                <div class="flex_center w-65px h-65px border border-dashed border-hex-E4E6E8 bg-hex-F9F9F9 text-hex-9D9AB9">
+                <div
+                  class="flex_center w-65px h-65px border border-dashed border-hex-E4E6E8 bg-hex-F9F9F9 text-hex-9D9AB9">
                   <i-akar-icons:plus class="text-xl" />
                 </div>
               </template>
@@ -111,14 +128,15 @@
           <el-form-item label="结对老师/组">
             <div class="showDiv">
               <div class="flex" style="flex-wrap: wrap;">
-                <div class="flex" style="margin-right: 20px;align-items: center;padding: 8px 0;" v-for="(item, index) in activeTeacherData" :key="index">
-                  <div class="typeItem">{{item.user_realname}}</div>
+                <div class="flex" style="margin-right: 20px;align-items: center;padding: 8px 0;"
+                  v-for="(item, index) in activeTeacherData" :key="index">
+                  <div class="typeItem">{{ item.user_realname }}</div>
                   <el-icon color="#00A3FF" class="pointer" @click="handleRemoveTeacher(index)">
                     <CircleClose />
                   </el-icon>
                 </div>
               </div>
-              <el-icon class="drop pointer" color="#a8abb2" :size="12" @click="showTeacher=!showTeacher">
+              <el-icon class="drop pointer" color="#a8abb2" :size="12" @click="showTeacher = !showTeacher">
                 <ArrowDownBold />
               </el-icon>
             </div>
@@ -143,16 +161,19 @@
                   </el-button>
                 </div>
               </div>
-              <div v-if="teacherData.length!=0">
+              <div v-if="teacherData.length != 0">
                 <el-checkbox-group v-model="activeTeacher" @change="initActiveTeacher">
-                  <el-checkbox v-for="(item, index) in teacherData" :key="index" :label="JSON.stringify(item)">{{item.user_realname}}({{item.user_name}})</el-checkbox>
+                  <el-checkbox v-for="(item, index) in teacherData" :key="index" :label="JSON.stringify(item)">{{
+                    item.user_realname
+                  }}({{ item.user_name }})</el-checkbox>
                 </el-checkbox-group>
               </div>
-              <el-empty v-if="teacherData.length==0" image-size="100" description="无数据" style="padding: 10px 0;" />
+              <el-empty v-if="teacherData.length == 0" :image-size="100" description="无数据" style="padding: 10px 0;" />
             </div>
           </el-form-item>
           <el-form-item label="结对班级">
-            <el-select v-model="activeClass" placeholder=" " multiple size="large" value-key="class_id" @change="initActiveClass">
+            <el-select v-model="activeClass" placeholder=" " multiple size="large" value-key="class_id"
+              @change="initActiveClass">
               <el-option v-for="item in classData" :key="item.class_id" :label="item.class_name" :value="item" />
             </el-select>
           </el-form-item>
@@ -160,18 +181,20 @@
           <div style="display: flex;">
             <el-form-item style="flex: 1;" label="是否手机端推荐课程">
               <el-radio-group v-model="formline.ks_sfsjdtjkc">
-                <el-radio v-for="item in sfsjdtjkcData" :key="item.v" :label="item.v" size="large">{{item.n}}</el-radio>
+                <el-radio v-for="item in sfsjdtjkcData" :key="item.v" :label="item.v" size="large">{{
+                  item.n
+                }}</el-radio>
               </el-radio-group>
             </el-form-item>
             <el-form-item style="flex: 1;margin-left: 50px;" label="是否精品">
               <el-radio-group v-model="formline.ks_sfjp">
-                <el-radio v-for="item in sfjpData" :key="item.v" :label="item.v" size="large">{{item.n}}</el-radio>
+                <el-radio v-for="item in sfjpData" :key="item.v" :label="item.v" size="large">{{ item.n }}</el-radio>
               </el-radio-group>
             </el-form-item>
           </div>
           <el-form-item label="是否需要审核">
             <el-radio-group v-model="formline.ks_sfxysh">
-              <el-radio v-for="item in sfxyshData" :key="item.v" :label="item.v" size="large">{{item.n}}</el-radio>
+              <el-radio v-for="item in sfxyshData" :key="item.v" :label="item.v" size="large">{{ item.n }}</el-radio>
             </el-radio-group>
           </el-form-item>
           <!-- <el-form-item label="审核状态">
@@ -184,7 +207,7 @@
               <el-option v-for="item in shdxData" :key="item.value" :label="item.label" :value="item.value" />
             </el-select>
           </el-form-item> -->
-          <el-form-item v-if="editId==''">
+          <el-form-item v-if="editId == ''">
             <el-checkbox class="read" v-model="isRead" label="已阅读并同意《课程上传协议》" size="large" />
           </el-form-item>
           <el-form-item>
@@ -200,6 +223,8 @@
 </template>
 
 <script>
+import { VueCropper } from 'vue-cropper'
+import 'vue-cropper/dist/index.css'
 import { grade_list, subject_list, ssyskc_list, upload_file, ssyskc_add, ssyskc_edit, ssyskc_detail } from "./api";
 
 import { Picture, FolderOpened, ArrowDownBold, CircleClose, Back, Right } from "@element-plus/icons-vue";
@@ -302,7 +327,7 @@ export default {
       commitLoading: false,
     }
   },
-  components: { Picture, FolderOpened, ElConfigProvider, ArrowDownBold, CircleClose, Back, Right },
+  components: { Picture, FolderOpened, ElConfigProvider, ArrowDownBold, CircleClose, Back, Right, VueCropper },
   methods: {
     goBack() {
       this.$router.go(-1);
@@ -528,6 +553,7 @@ export default {
         return false;
       }
 
+      console.log('file.raw :>> ', file.raw);
       upload_file(file.raw).then(res => {
         if (res.code == 1) {
           this.formline.ks_img = res.data.url;
@@ -567,7 +593,27 @@ export default {
         this.attachLoading = false;
       })
     },
-    submitForm(formName) {
+    async submitForm(formName) {
+      try {
+        await new Promise((resolve, reject) => {
+          this.$refs.cropper.getCropBlob(cropBlob => {
+            const cropFile = new File([cropBlob], 'crop.jpeg', { type: cropBlob.type })
+            console.log('cropFile :>> ', cropFile);
+            upload_file(cropFile).then(res => {
+              if (res.code == 1) {
+                this.formline.ks_img_cropping = res.data.url;
+                resolve(res.data.url)
+              } else {
+                reject(null)
+              }
+            })
+          })
+        })
+      } catch (error) {
+        return
+      }
+
+
       this.$refs[formName].validate((valid) => {
         if (valid && this.formline.ks_img != "" && this.formline.ks_kj != "" && !this.attachLoading) {
           this.formline.yys_id = this.linkWork.join(",");
@@ -640,43 +686,53 @@ export default {
     margin-bottom: 15px;
     background: #fff;
   }
+
   .pointer {
     cursor: pointer;
   }
+
   .title {
     font-size: 18px;
     color: #050026;
   }
+
   .subTitle {
     font-size: 14px;
     color: #949494;
     margin-left: 45px;
   }
+
   .formContent {
     width: 575px;
     margin: auto;
+
     .must {
       display: flex;
       align-items: center;
       margin-bottom: 22px;
+
       .label {
         color: #949494;
         font-size: 14px;
         margin-right: 15px;
+
         &::after {
           content: "*";
           color: #f35421;
           margin-left: 4px;
         }
       }
+
       .uploadDiv {
         flex: 1;
+
         .el-upload--picture-card {
           width: 180px;
           height: 96px;
         }
       }
     }
+
     .showType {
       width: 100%;
       height: 40px;
@@ -685,6 +741,7 @@ export default {
       display: flex;
       align-items: center;
       padding: 0 20px;
+
       .typeItem {
         color: #fff;
         font-size: 13px;
@@ -694,21 +751,26 @@ export default {
         line-height: 22px;
       }
     }
+
     .type {
       padding: 0 20px;
       margin-bottom: 10px;
+
       .flex {
         display: flex;
         align-items: baseline;
+
         .label {
           font-size: 13px;
           color: #333;
+
           &::after {
             content: "*";
             color: #f35421;
             margin-left: 4px;
           }
         }
+
         .valueDiv {
           margin-left: 15px;
           flex: 1;
@@ -718,10 +780,12 @@ export default {
           padding-bottom: 15px;
           font-weight: 400;
           font-size: 14px;
+
           .item {
             padding: 3px 5px;
             margin-right: 20px;
             margin-bottom: 5px;
+
             &.active {
               color: #00a3ff;
               border-radius: 6px;
@@ -731,6 +795,7 @@ export default {
         }
       }
     }
+
     .showDiv {
       position: relative;
       width: 100%;
@@ -738,11 +803,13 @@ export default {
       background: #f9f9f9;
       border-radius: 6px;
       padding: 0 30px 0 15px;
+
       .el-icon.drop {
         position: absolute;
         right: 15px;
         top: 15px;
       }
+
       .typeItem {
         background: #00a3ff;
         color: #fff;
@@ -753,21 +820,25 @@ export default {
         margin-right: 8px;
       }
     }
+
     .jdlsDiv {
       border: 1px solid #e4e6e8;
       border-radius: 6px;
       padding: 10px 12px;
       width: 100%;
+
       .operate {
         display: flex;
         justify-content: space-between;
         align-items: center;
         margin-bottom: 10px;
+
         .el-button {
           width: 32px;
           height: 32px;
         }
       }
+
       .searchValue {
         width: 278px;
         height: 40px;
@@ -775,6 +846,7 @@ export default {
         border-radius: 8px;
         overflow: hidden;
         position: relative;
+
         input {
           width: 100%;
           height: 100%;
@@ -783,6 +855,7 @@ export default {
           padding-left: 10px;
           background: #f6f8fa;
         }
+
         .searchBtn {
           width: 26px;
           height: 26px;
@@ -795,6 +868,7 @@ export default {
           text-align: center;
           vertical-align: middle;
           cursor: pointer;
+
           img {
             display: block;
             text-align: center;
@@ -802,14 +876,17 @@ export default {
           }
         }
       }
+
       .el-checkbox.el-checkbox--large {
         min-width: 80px;
         margin-right: 25px;
       }
     }
+
     .btnDiv {
       text-align: center;
       width: 100%;
+
       .el-button {
         background: #f4f4f4;
         border: none;
@@ -818,6 +895,7 @@ export default {
         color: #41387f;
         font-family: PingFangSC, PingFangSC-Semibold;
       }
+
       .el-button--primary {
         background: #00a3ff;
         margin-right: 80px;
@@ -833,6 +911,7 @@ export default {
   .el-card {
     margin-bottom: 15px;
     background: #fff;
+
     .el-form {
       .el-form-item {
         &.is-required {
@@ -840,6 +919,7 @@ export default {
             &::before {
               display: none;
             }
+
             &::after {
               content: "*";
               color: #f35421;
@@ -847,17 +927,21 @@ export default {
             }
           }
         }
+
         .el-form-item__label {
           color: #949494;
           font-size: 14px;
           position: relative;
         }
+
         .el-form-item__content {
           .el-select {
             width: 100%;
           }
+
           .el-input {
             width: 100%;
+
             .el-input__wrapper {
               width: 100%;
               box-shadow: none;
@@ -865,6 +949,7 @@ export default {
               border-radius: 6px;
             }
           }
+
           .el-textarea {
             .el-textarea__inner {
               box-shadow: none;
@@ -873,31 +958,37 @@ export default {
               // color: #d0d0d0;
             }
           }
+
           .el-date-editor {
             box-shadow: none;
             background: #f9f9f9;
             border-radius: 6px;
           }
+
           .el-checkbox.read {
             .el-checkbox__inner {
               border-radius: 50%;
             }
           }
+
           .el-input__inner {
             // color: #d0d0d0;
           }
         }
       }
+
       .uploadDiv {
         .mainUpload {
           .el-upload--picture-card {
             width: 180px;
             height: 96px;
           }
+
           .el-upload-list--picture-card .el-upload-list__item {
             display: none;
           }
         }
+
         .attachUpload {
           .el-upload-dragger {
             width: 65px;
@@ -911,9 +1002,10 @@ export default {
     }
   }
 }
+
 .ssystime {
   .el-picker-panel__footer {
     display: none;
   }
 }
-</style>
+</style>

+ 1 - 1
src/pages/ysgc/index.vue

@@ -566,7 +566,7 @@ export default {
       margin: 42px auto;
       .kc {
         width: 395px;
-        height: 232px;
+        height: 395px;
         overflow: hidden;
         border-radius: 12px;
         box-shadow: 0px 10px 24px 0px rgba(161, 153, 168, 0.18);