Li Kui 1 рік тому
батько
коміт
27cb958c2e

+ 3 - 3
src/components/Cropper/src/CropperAvatar.vue

@@ -20,7 +20,7 @@
       {{ btnText ? btnText : t('component.cropper.selectImage') }}
     </a-button>
 
-    <CopperModal
+    <CropperModal
       @register="register"
       @upload-success="handleUploadSuccess"
       :uploadApi="uploadApi"
@@ -39,7 +39,7 @@
     watch,
     PropType,
   } from 'vue';
-  import CopperModal from './CopperModal.vue';
+  import CropperModal from './CropperModal.vue';
   import { useDesign } from '/@/hooks/web/useDesign';
   import { useModal } from '/@/components/Modal';
   import { useMessage } from '/@/hooks/web/useMessage';
@@ -58,7 +58,7 @@
 
   export default defineComponent({
     name: 'CropperAvatar',
-    components: { CopperModal, Icon },
+    components: { CropperModal, Icon },
     props,
     emits: ['update:value', 'change'],
     setup(props, { emit, expose }) {

+ 284 - 284
src/components/Cropper/src/CopperModal.vue → src/components/Cropper/src/CropperModal.vue

@@ -1,284 +1,284 @@
-<template>
-  <BasicModal
-    v-bind="$attrs"
-    @register="register"
-    :title="t('component.cropper.modalTitle')"
-    width="800px"
-    :canFullscreen="false"
-    @ok="handleOk"
-    :okText="t('component.cropper.okText')"
-  >
-    <div :class="prefixCls">
-      <div :class="`${prefixCls}-left`">
-        <div :class="`${prefixCls}-cropper`">
-          <CropperImage
-            v-if="src"
-            :src="src"
-            height="300px"
-            :circled="circled"
-            @cropend="handleCropend"
-            @ready="handleReady"
-          />
-        </div>
-
-        <div :class="`${prefixCls}-toolbar`">
-          <Upload :fileList="[]" accept="image/*" :beforeUpload="handleBeforeUpload">
-            <Tooltip :title="t('component.cropper.selectImage')" placement="bottom">
-              <a-button size="small" preIcon="ant-design:upload-outlined" type="primary" />
-            </Tooltip>
-          </Upload>
-          <Space>
-            <Tooltip :title="t('component.cropper.btn_reset')" placement="bottom">
-              <a-button
-                type="primary"
-                preIcon="ant-design:reload-outlined"
-                size="small"
-                :disabled="!src"
-                @click="handlerToolbar('reset')"
-              />
-            </Tooltip>
-            <Tooltip :title="t('component.cropper.btn_rotate_left')" placement="bottom">
-              <a-button
-                type="primary"
-                preIcon="ant-design:rotate-left-outlined"
-                size="small"
-                :disabled="!src"
-                @click="handlerToolbar('rotate', -45)"
-              />
-            </Tooltip>
-            <Tooltip :title="t('component.cropper.btn_rotate_right')" placement="bottom">
-              <a-button
-                type="primary"
-                preIcon="ant-design:rotate-right-outlined"
-                size="small"
-                :disabled="!src"
-                @click="handlerToolbar('rotate', 45)"
-              />
-            </Tooltip>
-            <Tooltip :title="t('component.cropper.btn_scale_x')" placement="bottom">
-              <a-button
-                type="primary"
-                preIcon="vaadin:arrows-long-h"
-                size="small"
-                :disabled="!src"
-                @click="handlerToolbar('scaleX')"
-              />
-            </Tooltip>
-            <Tooltip :title="t('component.cropper.btn_scale_y')" placement="bottom">
-              <a-button
-                type="primary"
-                preIcon="vaadin:arrows-long-v"
-                size="small"
-                :disabled="!src"
-                @click="handlerToolbar('scaleY')"
-              />
-            </Tooltip>
-            <Tooltip :title="t('component.cropper.btn_zoom_in')" placement="bottom">
-              <a-button
-                type="primary"
-                preIcon="ant-design:zoom-in-outlined"
-                size="small"
-                :disabled="!src"
-                @click="handlerToolbar('zoom', 0.1)"
-              />
-            </Tooltip>
-            <Tooltip :title="t('component.cropper.btn_zoom_out')" placement="bottom">
-              <a-button
-                type="primary"
-                preIcon="ant-design:zoom-out-outlined"
-                size="small"
-                :disabled="!src"
-                @click="handlerToolbar('zoom', -0.1)"
-              />
-            </Tooltip>
-          </Space>
-        </div>
-      </div>
-      <div :class="`${prefixCls}-right`">
-        <div :class="`${prefixCls}-preview`">
-          <img :src="previewSource" v-if="previewSource" :alt="t('component.cropper.preview')" />
-        </div>
-        <template v-if="previewSource">
-          <div :class="`${prefixCls}-group`">
-            <Avatar :src="previewSource" size="large" />
-            <Avatar :src="previewSource" :size="48" />
-            <Avatar :src="previewSource" :size="64" />
-            <Avatar :src="previewSource" :size="80" />
-          </div>
-        </template>
-      </div>
-    </div>
-  </BasicModal>
-</template>
-<script lang="ts">
-  import type { CropendResult, Cropper } from './typing';
-
-  import { defineComponent, ref, PropType } from 'vue';
-  import CropperImage from './Cropper.vue';
-  import { Space, Upload, Avatar, Tooltip } from 'ant-design-vue';
-  import { useDesign } from '/@/hooks/web/useDesign';
-  import { BasicModal, useModalInner } from '/@/components/Modal';
-  import { dataURLtoBlob } from '/@/utils/file/base64Conver';
-  import { isFunction } from '/@/utils/is';
-  import { useI18n } from '/@/hooks/web/useI18n';
-
-  type apiFunParams = { file: Blob; name: string; filename: string };
-
-  const props = {
-    circled: { type: Boolean, default: true },
-    uploadApi: {
-      type: Function as PropType<(params: apiFunParams) => Promise<any>>,
-    },
-    src: { type: String },
-  };
-
-  export default defineComponent({
-    name: 'CropperModal',
-    components: { BasicModal, Space, CropperImage, Upload, Avatar, Tooltip },
-    props,
-    emits: ['uploadSuccess', 'register'],
-    setup(props, { emit }) {
-      let filename = '';
-      const src = ref(props.src || '');
-      const previewSource = ref('');
-      const cropper = ref<Cropper>();
-      let scaleX = 1;
-      let scaleY = 1;
-
-      const { prefixCls } = useDesign('cropper-am');
-      const [register, { closeModal, setModalProps }] = useModalInner();
-      const { t } = useI18n();
-
-      // Block upload
-      function handleBeforeUpload(file: File) {
-        const reader = new FileReader();
-        reader.readAsDataURL(file);
-        src.value = '';
-        previewSource.value = '';
-        reader.onload = function (e) {
-          src.value = (e.target?.result as string) ?? '';
-          filename = file.name;
-        };
-        return false;
-      }
-
-      function handleCropend({ imgBase64 }: CropendResult) {
-        previewSource.value = imgBase64;
-      }
-
-      function handleReady(cropperInstance: Cropper) {
-        cropper.value = cropperInstance;
-      }
-
-      function handlerToolbar(event: string, arg?: number) {
-        if (event === 'scaleX') {
-          scaleX = arg = scaleX === -1 ? 1 : -1;
-        }
-        if (event === 'scaleY') {
-          scaleY = arg = scaleY === -1 ? 1 : -1;
-        }
-        cropper?.value?.[event]?.(arg);
-      }
-
-      async function handleOk() {
-        const uploadApi = props.uploadApi;
-        if (uploadApi && isFunction(uploadApi)) {
-          const blob = dataURLtoBlob(previewSource.value);
-          try {
-            setModalProps({ confirmLoading: true });
-            const result = await uploadApi({ name: 'file', file: blob, filename });
-            emit('uploadSuccess', { source: previewSource.value, data: result.url });
-            closeModal();
-          } finally {
-            setModalProps({ confirmLoading: false });
-          }
-        }
-      }
-
-      return {
-        t,
-        prefixCls,
-        src,
-        register,
-        previewSource,
-        handleBeforeUpload,
-        handleCropend,
-        handleReady,
-        handlerToolbar,
-        handleOk,
-      };
-    },
-  });
-</script>
-
-<style lang="less">
-  @prefix-cls: ~'@{namespace}-cropper-am';
-
-  .@{prefix-cls} {
-    display: flex;
-
-    &-left,
-    &-right {
-      height: 340px;
-    }
-
-    &-left {
-      width: 55%;
-    }
-
-    &-right {
-      width: 45%;
-    }
-
-    &-cropper {
-      height: 300px;
-      background: #eee;
-      background-image: linear-gradient(
-          45deg,
-          rgb(0 0 0 / 25%) 25%,
-          transparent 0,
-          transparent 75%,
-          rgb(0 0 0 / 25%) 0
-        ),
-        linear-gradient(
-          45deg,
-          rgb(0 0 0 / 25%) 25%,
-          transparent 0,
-          transparent 75%,
-          rgb(0 0 0 / 25%) 0
-        );
-      background-position: 0 0, 12px 12px;
-      background-size: 24px 24px;
-    }
-
-    &-toolbar {
-      display: flex;
-      align-items: center;
-      justify-content: space-between;
-      margin-top: 10px;
-    }
-
-    &-preview {
-      width: 220px;
-      height: 220px;
-      margin: 0 auto;
-      overflow: hidden;
-      border: 1px solid @border-color-base;
-      border-radius: 50%;
-
-      img {
-        width: 100%;
-        height: 100%;
-      }
-    }
-
-    &-group {
-      display: flex;
-      align-items: center;
-      justify-content: space-around;
-      margin-top: 8px;
-      padding-top: 8px;
-      border-top: 1px solid @border-color-base;
-    }
-  }
-</style>
+<template>
+  <BasicModal
+    v-bind="$attrs"
+    @register="register"
+    :title="t('component.cropper.modalTitle')"
+    width="800px"
+    :canFullscreen="false"
+    @ok="handleOk"
+    :okText="t('component.cropper.okText')"
+  >
+    <div :class="prefixCls">
+      <div :class="`${prefixCls}-left`">
+        <div :class="`${prefixCls}-cropper`">
+          <CropperImage
+            v-if="src"
+            :src="src"
+            height="300px"
+            :circled="circled"
+            @cropend="handleCropend"
+            @ready="handleReady"
+          />
+        </div>
+
+        <div :class="`${prefixCls}-toolbar`">
+          <Upload :fileList="[]" accept="image/*" :beforeUpload="handleBeforeUpload">
+            <Tooltip :title="t('component.cropper.selectImage')" placement="bottom">
+              <a-button size="small" preIcon="ant-design:upload-outlined" type="primary" />
+            </Tooltip>
+          </Upload>
+          <Space>
+            <Tooltip :title="t('component.cropper.btn_reset')" placement="bottom">
+              <a-button
+                type="primary"
+                preIcon="ant-design:reload-outlined"
+                size="small"
+                :disabled="!src"
+                @click="handlerToolbar('reset')"
+              />
+            </Tooltip>
+            <Tooltip :title="t('component.cropper.btn_rotate_left')" placement="bottom">
+              <a-button
+                type="primary"
+                preIcon="ant-design:rotate-left-outlined"
+                size="small"
+                :disabled="!src"
+                @click="handlerToolbar('rotate', -45)"
+              />
+            </Tooltip>
+            <Tooltip :title="t('component.cropper.btn_rotate_right')" placement="bottom">
+              <a-button
+                type="primary"
+                preIcon="ant-design:rotate-right-outlined"
+                size="small"
+                :disabled="!src"
+                @click="handlerToolbar('rotate', 45)"
+              />
+            </Tooltip>
+            <Tooltip :title="t('component.cropper.btn_scale_x')" placement="bottom">
+              <a-button
+                type="primary"
+                preIcon="vaadin:arrows-long-h"
+                size="small"
+                :disabled="!src"
+                @click="handlerToolbar('scaleX')"
+              />
+            </Tooltip>
+            <Tooltip :title="t('component.cropper.btn_scale_y')" placement="bottom">
+              <a-button
+                type="primary"
+                preIcon="vaadin:arrows-long-v"
+                size="small"
+                :disabled="!src"
+                @click="handlerToolbar('scaleY')"
+              />
+            </Tooltip>
+            <Tooltip :title="t('component.cropper.btn_zoom_in')" placement="bottom">
+              <a-button
+                type="primary"
+                preIcon="ant-design:zoom-in-outlined"
+                size="small"
+                :disabled="!src"
+                @click="handlerToolbar('zoom', 0.1)"
+              />
+            </Tooltip>
+            <Tooltip :title="t('component.cropper.btn_zoom_out')" placement="bottom">
+              <a-button
+                type="primary"
+                preIcon="ant-design:zoom-out-outlined"
+                size="small"
+                :disabled="!src"
+                @click="handlerToolbar('zoom', -0.1)"
+              />
+            </Tooltip>
+          </Space>
+        </div>
+      </div>
+      <div :class="`${prefixCls}-right`">
+        <div :class="`${prefixCls}-preview`">
+          <img :src="previewSource" v-if="previewSource" :alt="t('component.cropper.preview')" />
+        </div>
+        <template v-if="previewSource">
+          <div :class="`${prefixCls}-group`">
+            <Avatar :src="previewSource" size="large" />
+            <Avatar :src="previewSource" :size="48" />
+            <Avatar :src="previewSource" :size="64" />
+            <Avatar :src="previewSource" :size="80" />
+          </div>
+        </template>
+      </div>
+    </div>
+  </BasicModal>
+</template>
+<script lang="ts">
+  import type { CropendResult, Cropper } from './typing';
+
+  import { defineComponent, ref, PropType } from 'vue';
+  import CropperImage from './Cropper.vue';
+  import { Space, Upload, Avatar, Tooltip } from 'ant-design-vue';
+  import { useDesign } from '/@/hooks/web/useDesign';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import { dataURLtoBlob } from '/@/utils/file/base64Conver';
+  import { isFunction } from '/@/utils/is';
+  import { useI18n } from '/@/hooks/web/useI18n';
+
+  type apiFunParams = { file: Blob; name: string; filename: string };
+
+  const props = {
+    circled: { type: Boolean, default: true },
+    uploadApi: {
+      type: Function as PropType<(params: apiFunParams) => Promise<any>>,
+    },
+    src: { type: String },
+  };
+
+  export default defineComponent({
+    name: 'CropperModal',
+    components: { BasicModal, Space, CropperImage, Upload, Avatar, Tooltip },
+    props,
+    emits: ['uploadSuccess', 'register'],
+    setup(props, { emit }) {
+      let filename = '';
+      const src = ref(props.src || '');
+      const previewSource = ref('');
+      const cropper = ref<Cropper>();
+      let scaleX = 1;
+      let scaleY = 1;
+
+      const { prefixCls } = useDesign('cropper-am');
+      const [register, { closeModal, setModalProps }] = useModalInner();
+      const { t } = useI18n();
+
+      // Block upload
+      function handleBeforeUpload(file: File) {
+        const reader = new FileReader();
+        reader.readAsDataURL(file);
+        src.value = '';
+        previewSource.value = '';
+        reader.onload = function (e) {
+          src.value = (e.target?.result as string) ?? '';
+          filename = file.name;
+        };
+        return false;
+      }
+
+      function handleCropend({ imgBase64 }: CropendResult) {
+        previewSource.value = imgBase64;
+      }
+
+      function handleReady(cropperInstance: Cropper) {
+        cropper.value = cropperInstance;
+      }
+
+      function handlerToolbar(event: string, arg?: number) {
+        if (event === 'scaleX') {
+          scaleX = arg = scaleX === -1 ? 1 : -1;
+        }
+        if (event === 'scaleY') {
+          scaleY = arg = scaleY === -1 ? 1 : -1;
+        }
+        cropper?.value?.[event]?.(arg);
+      }
+
+      async function handleOk() {
+        const uploadApi = props.uploadApi;
+        if (uploadApi && isFunction(uploadApi)) {
+          const blob = dataURLtoBlob(previewSource.value);
+          try {
+            setModalProps({ confirmLoading: true });
+            const result = await uploadApi({ name: 'file', file: blob, filename });
+            emit('uploadSuccess', { source: previewSource.value, data: result.url });
+            closeModal();
+          } finally {
+            setModalProps({ confirmLoading: false });
+          }
+        }
+      }
+
+      return {
+        t,
+        prefixCls,
+        src,
+        register,
+        previewSource,
+        handleBeforeUpload,
+        handleCropend,
+        handleReady,
+        handlerToolbar,
+        handleOk,
+      };
+    },
+  });
+</script>
+
+<style lang="less">
+  @prefix-cls: ~'@{namespace}-cropper-am';
+
+  .@{prefix-cls} {
+    display: flex;
+
+    &-left,
+    &-right {
+      height: 340px;
+    }
+
+    &-left {
+      width: 55%;
+    }
+
+    &-right {
+      width: 45%;
+    }
+
+    &-cropper {
+      height: 300px;
+      background: #eee;
+      background-image: linear-gradient(
+          45deg,
+          rgb(0 0 0 / 25%) 25%,
+          transparent 0,
+          transparent 75%,
+          rgb(0 0 0 / 25%) 0
+        ),
+        linear-gradient(
+          45deg,
+          rgb(0 0 0 / 25%) 25%,
+          transparent 0,
+          transparent 75%,
+          rgb(0 0 0 / 25%) 0
+        );
+      background-position: 0 0, 12px 12px;
+      background-size: 24px 24px;
+    }
+
+    &-toolbar {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      margin-top: 10px;
+    }
+
+    &-preview {
+      width: 220px;
+      height: 220px;
+      margin: 0 auto;
+      overflow: hidden;
+      border: 1px solid @border-color-base;
+      border-radius: 50%;
+
+      img {
+        width: 100%;
+        height: 100%;
+      }
+    }
+
+    &-group {
+      display: flex;
+      align-items: center;
+      justify-content: space-around;
+      margin-top: 8px;
+      padding-top: 8px;
+      border-top: 1px solid @border-color-base;
+    }
+  }
+</style>