Browse Source

背景设置自定义模式增加锁定比例

dsy 3 days ago
parent
commit
a654c7fea3

+ 1 - 1
.env

@@ -11,4 +11,4 @@ VUE_APP_BookWebSI = '/GCLSBookWebSI/ServiceInterface'
 VUE_APP_EepServer = '/EEPServer/SI'
 VUE_APP_EepServer = '/EEPServer/SI'
 
 
 #version
 #version
-VUE_APP_VERSION = '2026.05.09'
+VUE_APP_VERSION = '2026.05.11'

+ 54 - 0
src/views/book/courseware/create/components/SetBackground.vue

@@ -86,6 +86,9 @@
               <el-button v-if="cropMode" size="mini" @click="cancelRectCrop">取消</el-button>
               <el-button v-if="cropMode" size="mini" @click="cancelRectCrop">取消</el-button>
               <el-button v-if="cropMode" size="mini" type="primary" @click="applyRectCrop">应用</el-button>
               <el-button v-if="cropMode" size="mini" type="primary" @click="applyRectCrop">应用</el-button>
             </div>
             </div>
+            <div v-if="background.imageMode === imageModeList[3].value">
+              <el-checkbox v-model="lockScale">锁定比例</el-checkbox>
+            </div>
           </div>
           </div>
         </div>
         </div>
         <div class="setup-item">
         <div class="setup-item">
@@ -191,6 +194,7 @@ export default {
         startX: 0,
         startX: 0,
         startY: 0,
         startY: 0,
         type: '',
         type: '',
+        aspectRatio: 1, // 锁定比例时的宽高比
       },
       },
       cropMode: false,
       cropMode: false,
       crop: {
       crop: {
@@ -232,6 +236,7 @@ export default {
         { label: '平铺', value: 'fill' },
         { label: '平铺', value: 'fill' },
         { label: '自定义', value: 'auto' },
         { label: '自定义', value: 'auto' },
       ],
       ],
+      lockScale: false, // 是否锁定比例(仅自定义模式)
     };
     };
   },
   },
   computed: {
   computed: {
@@ -341,11 +346,13 @@ export default {
     dragStart(event, cursor, type) {
     dragStart(event, cursor, type) {
       if (this.cropMode) return;
       if (this.cropMode) return;
       const { clientX, clientY } = event;
       const { clientX, clientY } = event;
+      const aspectRatio = this.imgData.height ? this.imgData.width / this.imgData.height : 1;
       this.drag = {
       this.drag = {
         dragging: true,
         dragging: true,
         startX: clientX,
         startX: clientX,
         startY: clientY,
         startY: clientY,
         type,
         type,
+        aspectRatio,
       };
       };
 
 
       document.querySelector('.el-dialog__wrapper').style.cursor = cursor;
       document.querySelector('.el-dialog__wrapper').style.cursor = cursor;
@@ -377,6 +384,7 @@ export default {
       if (!this.drag.dragging) return;
       if (!this.drag.dragging) return;
       const { clientX, clientY } = event;
       const { clientX, clientY } = event;
       const { startX, startY, type } = this.drag;
       const { startX, startY, type } = this.drag;
+      const prevImgData = { ...this.imgData };
 
 
       const widthDiff = clientX - startX;
       const widthDiff = clientX - startX;
       const heightDiff = clientY - startY;
       const heightDiff = clientY - startY;
@@ -422,11 +430,57 @@ export default {
         this.imgData.left = Math.min(this.maxWidth - this.imgData.width, Math.max(0, this.imgData.left + widthDiff));
         this.imgData.left = Math.min(this.maxWidth - this.imgData.width, Math.max(0, this.imgData.left + widthDiff));
       }
       }
 
 
+      if (this.shouldLockScale(type)) {
+        this.applyLockedScaleResize(type, prevImgData);
+      }
+
       this.drag.startX = clientX;
       this.drag.startX = clientX;
       this.drag.startY = clientY;
       this.drag.startY = clientY;
       this.syncImageDisplayRect();
       this.syncImageDisplayRect();
     },
     },
     /**
     /**
+     * 判断在当前拖动类型下是否应该锁定比例调整尺寸
+     * @param {string} type 拖动类型
+     * @returns {boolean} 是否应该锁定比例调整尺寸
+     */
+    shouldLockScale(type) {
+      return this.background.imageMode === 'auto' && this.lockScale && type !== 'move';
+    },
+    /**
+     * 在锁定比例的情况下调整尺寸,确保宽高比保持不变,并且不会超出边界
+     * @param {string} type 拖动类型
+     * @param {object} prevImgData 拖动前的图片数据,用于计算边界限制
+     */
+    applyLockedScaleResize(type, prevImgData) {
+      const ratio = this.drag.aspectRatio || 1;
+      if (!ratio) return;
+
+      let width = type === 'top' || type === 'bottom' ? this.imgData.height * ratio : this.imgData.width;
+      let height = width / ratio;
+
+      // 根据拖动方向计算允许的最大宽高,确保在锁定比例时不会超出边界
+      const widthLimit = type.includes('left')
+        ? prevImgData.left + prevImgData.width
+        : this.maxWidth - prevImgData.left;
+      const heightLimit = type.includes('top')
+        ? prevImgData.top + prevImgData.height
+        : this.maxHeight - prevImgData.top;
+      const maxWidthByHeight = heightLimit * ratio;
+      const safeWidth = Math.max(1, Math.min(width, widthLimit, maxWidthByHeight));
+
+      width = safeWidth;
+      height = width / ratio;
+
+      // 根据拖动方向计算新的 left 和 top,确保在锁定比例时图片位置调整合理
+      const left = type.includes('left') ? prevImgData.left + prevImgData.width - width : prevImgData.left;
+      const top = type.includes('top') ? prevImgData.top + prevImgData.height - height : prevImgData.top;
+
+      this.imgData.width = width;
+      this.imgData.height = height;
+      this.imgData.left = Math.min(this.maxWidth - width, Math.max(0, left));
+      this.imgData.top = Math.min(this.maxHeight - height, Math.max(0, top));
+    },
+    /**
      * 鼠标抬起
      * 鼠标抬起
      */
      */
     mouseUp() {
     mouseUp() {

+ 54 - 0
src/views/book/courseware/create/components/SetComponentBackground.vue

@@ -77,6 +77,9 @@
               <el-button v-if="cropMode" size="mini" @click="cancelRectCrop">取消</el-button>
               <el-button v-if="cropMode" size="mini" @click="cancelRectCrop">取消</el-button>
               <el-button v-if="cropMode" size="mini" type="primary" @click="applyRectCrop">应用</el-button>
               <el-button v-if="cropMode" size="mini" type="primary" @click="applyRectCrop">应用</el-button>
             </div>
             </div>
+            <div v-if="background.imageMode === imageModeList[3].value">
+              <el-checkbox v-model="lockScale">锁定比例</el-checkbox>
+            </div>
           </div>
           </div>
         </div>
         </div>
         <div class="setup-item">
         <div class="setup-item">
@@ -181,6 +184,7 @@ export default {
         startX: 0,
         startX: 0,
         startY: 0,
         startY: 0,
         type: '',
         type: '',
+        aspectRatio: 1, // 锁定比例时的宽高比
       },
       },
       cropMode: false,
       cropMode: false,
       crop: {
       crop: {
@@ -220,6 +224,7 @@ export default {
         { label: '平铺', value: 'fill' },
         { label: '平铺', value: 'fill' },
         { label: '自定义', value: 'auto' },
         { label: '自定义', value: 'auto' },
       ],
       ],
+      lockScale: false, // 是否锁定比例(仅自定义模式)
     };
     };
   },
   },
   computed: {
   computed: {
@@ -354,11 +359,13 @@ export default {
     dragStart(event, cursor, type) {
     dragStart(event, cursor, type) {
       if (this.cropMode) return;
       if (this.cropMode) return;
       const { clientX, clientY } = event;
       const { clientX, clientY } = event;
+      const aspectRatio = this.imgData.height ? this.imgData.width / this.imgData.height : 1;
       this.drag = {
       this.drag = {
         dragging: true,
         dragging: true,
         startX: clientX,
         startX: clientX,
         startY: clientY,
         startY: clientY,
         type,
         type,
+        aspectRatio,
       };
       };
 
 
       document.querySelector('.el-dialog__wrapper').style.cursor = cursor;
       document.querySelector('.el-dialog__wrapper').style.cursor = cursor;
@@ -390,6 +397,7 @@ export default {
       if (!this.drag.dragging) return;
       if (!this.drag.dragging) return;
       const { clientX, clientY } = event;
       const { clientX, clientY } = event;
       const { startX, startY, type } = this.drag;
       const { startX, startY, type } = this.drag;
+      const prevImgData = { ...this.imgData };
 
 
       const widthDiff = clientX - startX;
       const widthDiff = clientX - startX;
       const heightDiff = clientY - startY;
       const heightDiff = clientY - startY;
@@ -435,11 +443,57 @@ export default {
         this.imgData.left = Math.min(this.maxWidth - this.imgData.width, Math.max(0, this.imgData.left + widthDiff));
         this.imgData.left = Math.min(this.maxWidth - this.imgData.width, Math.max(0, this.imgData.left + widthDiff));
       }
       }
 
 
+      if (this.shouldLockScale(type)) {
+        this.applyLockedScaleResize(type, prevImgData);
+      }
+
       this.drag.startX = clientX;
       this.drag.startX = clientX;
       this.drag.startY = clientY;
       this.drag.startY = clientY;
       this.syncImageDisplayRect();
       this.syncImageDisplayRect();
     },
     },
     /**
     /**
+     * 判断在当前拖动类型下是否应该锁定比例调整尺寸
+     * @param {string} type 拖动类型
+     * @returns {boolean} 是否应该锁定比例调整尺寸
+     */
+    shouldLockScale(type) {
+      return this.background.imageMode === 'auto' && this.lockScale && type !== 'move';
+    },
+    /**
+     * 在锁定比例的情况下调整尺寸,确保宽高比保持不变,并且不会超出边界
+     * @param {string} type 拖动类型
+     * @param {object} prevImgData 拖动前的图片数据,用于计算边界限制
+     */
+    applyLockedScaleResize(type, prevImgData) {
+      const ratio = this.drag.aspectRatio || 1;
+      if (!ratio) return;
+
+      let width = type === 'top' || type === 'bottom' ? this.imgData.height * ratio : this.imgData.width;
+      let height = width / ratio;
+
+      // 根据拖动方向计算允许的最大宽高,确保在锁定比例时不会超出边界
+      const widthLimit = type.includes('left')
+        ? prevImgData.left + prevImgData.width
+        : this.maxWidth - prevImgData.left;
+      const heightLimit = type.includes('top')
+        ? prevImgData.top + prevImgData.height
+        : this.maxHeight - prevImgData.top;
+      const maxWidthByHeight = heightLimit * ratio;
+      const safeWidth = Math.max(1, Math.min(width, widthLimit, maxWidthByHeight));
+
+      width = safeWidth;
+      height = width / ratio;
+
+      // 根据拖动方向计算新的 left 和 top,确保在锁定比例时图片位置调整合理
+      const left = type.includes('left') ? prevImgData.left + prevImgData.width - width : prevImgData.left;
+      const top = type.includes('top') ? prevImgData.top + prevImgData.height - height : prevImgData.top;
+
+      this.imgData.width = width;
+      this.imgData.height = height;
+      this.imgData.left = Math.min(this.maxWidth - width, Math.max(0, left));
+      this.imgData.top = Math.min(this.maxHeight - height, Math.max(0, top));
+    },
+    /**
      * 鼠标抬起
      * 鼠标抬起
      */
      */
     mouseUp() {
     mouseUp() {