Ver código fonte

更新组件

lex-xin 3 anos atrás
pai
commit
be267a0971

+ 9 - 0
package-lock.json

@@ -6960,6 +6960,15 @@
       "resolved": "https://registry.npmmirror.com/vue-cropper/-/vue-cropper-1.0.3.tgz",
       "integrity": "sha512-yDrZkE4H5vOiMA9WQHE+6rmXrZ1S9TMZasEPAZPKg/2I/nySHL4ECD1lNxt7+ofTPKT+9+2sQkCwagPqEqiqJg=="
     },
+    "vue-cropper-h5": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmmirror.com/vue-cropper-h5/-/vue-cropper-h5-2.0.1.tgz",
+      "integrity": "sha512-3d6MP1zUGiZGxwrUo3ShZ8JYdyF7JUUryJBHaz/zC/3ZYXqnU8srvTGEjN0w7qhZwTkpArvpd0f3OkhXsaEtdw==",
+      "requires": {
+        "vue": "^3.2.16",
+        "vue-cropper": "^1.0.2"
+      }
+    },
     "vue-eslint-parser": {
       "version": "8.0.1",
       "resolved": "https://registry.npmmirror.com/vue-eslint-parser/-/vue-eslint-parser-8.0.1.tgz",

+ 1 - 0
package.json

@@ -32,6 +32,7 @@
     "vant": "^3.3.7",
     "vue": "^3.2.26",
     "vue-cropper": "^1.0.3",
+    "vue-cropper-h5": "^2.0.1",
     "vue-router": "^4.0.12",
     "vuex": "^4.0.2"
   },

Diferenças do arquivo suprimidas por serem muito extensas
+ 42 - 0
src/components/col-cropper/index.module.less


+ 396 - 0
src/components/col-cropper/index.tsx

@@ -0,0 +1,396 @@
+import { defineComponent } from "vue";
+import 'vue-cropper/dist/index.css'
+import { VueCropper } from 'vue-cropper';
+import styles from './index.module.less'
+
+export default defineComponent({
+  name: "col-cropper",
+  components: { VueCropper },
+  props: {
+    hideInput: {
+      type: Boolean,
+      default: false
+    },
+    option: {
+      type: Object
+    },
+    onCancelTailor: {
+      type: Function,
+      default: () => {}
+    }, // 取消
+    getBase64Data: {
+      type: Function,
+      default: () => {}
+    },
+    getBlob: {
+      type: Function,
+      default: () => {}
+    },
+    getFile: {
+      type: Function,
+      default: () => {}
+    },
+    imgOriginF: {
+      type: Function,
+      default: () => {}
+    },
+  },
+  data() {
+    return {
+      img: "",
+      config: {
+        ceilbutton: false, //顶部按钮,默认底部
+        outputSize: 1, //裁剪生成图片的质量
+        outputType: "png", //裁剪生成图片的格式,默认png
+        info: false, //裁剪框的大小信息
+        canScale: true, //图片是否允许滚轮缩放
+        autoCrop: false, //是否默认生成截图框
+        autoCropWidth: 0, //默认生成截图框宽度
+        autoCropHeight: 0, //默认生成截图框高度
+        fixed: true, //是否开启截图框宽高固定比例
+        fixedNumber: [1, 1], //截图框的宽高比例
+        full: false, //是否输出原图比例的截图
+        fixedBox: true, //固定截图框大小 不允许改变
+        canMove: true, //上传图片是否可以移动
+        canMoveBox: false, //截图框能否拖动
+        original: false, //上传图片按照原始比例渲染
+        centerBox: true, //截图框是否被限制在图片里面
+        high: true, //是否按照设备的dpr 输出等比例图片
+        infoTrue: false, //true 为展示真实输出图片宽高 false 展示看到的截图框宽高
+        maxImgSize: 2000, //限制图片最大宽度和高度
+        enlarge: 1, //图片根据截图框输出比例倍数
+        mode: "100%", //图片默认渲染方式
+        cancelButtonText:"取消",//取消按钮文本
+        confirmButtonText:"确定",//确定按钮文本
+        cancelButtonBackgroundColor:"#606266",//取消按钮背景色
+        confirmButtonBackgroundColor:"#ed594c",//确定按钮背景色
+        cancelButtonTextColor:"#ffffff",//取消按钮字体色
+        confirmButtonTextColor:"#ffffff",//确定按钮字体色
+      }
+    }
+  },
+  mounted() {
+    this.config = Object.assign(this.config, this.option)
+  },
+  methods: {
+    //添加网格线
+    addSlide() {
+      if (document.getElementById("vertical") == null) {
+        let box = document.getElementsByClassName("cropper-crop-box")[0];
+        //左网格线
+        let verticalLeft = document.createElement("div");
+        verticalLeft.id = "vertical";
+        verticalLeft.style.width = "1px";
+        verticalLeft.style.height = "100%";
+        verticalLeft.style.top = "0px";
+        verticalLeft.style.left = "33%";
+        verticalLeft.style.position = "absolute";
+        verticalLeft.style.backgroundColor = "#fff";
+        verticalLeft.style.zIndex = "522";
+        verticalLeft.style.opacity = "0.5";
+        //右网格线
+        let verticalRight = document.createElement("div");
+        verticalRight.style.width = "1px";
+        verticalRight.style.height = "100%";
+        verticalRight.style.top = "0px";
+        verticalRight.style.right = "33%";
+        verticalRight.style.position = "absolute";
+        verticalRight.style.backgroundColor = "#fff";
+        verticalRight.style.zIndex = "522";
+        verticalRight.style.opacity = "0.5";
+        //上网格线
+        let verticalTop = document.createElement("div");
+        verticalTop.style.width = "100%";
+        verticalTop.style.height = "1px";
+        verticalTop.style.top = "33%";
+        verticalTop.style.left = "0px";
+        verticalTop.style.position = "absolute";
+        verticalTop.style.backgroundColor = "#fff";
+        verticalTop.style.zIndex = "522";
+        verticalTop.style.opacity = "0.5";
+        //下网格线
+        let verticalBottom = document.createElement("div");
+        verticalBottom.style.width = "100%";
+        verticalBottom.style.height = "1px";
+        verticalBottom.style.bottom = "33%";
+        verticalBottom.style.left = "0px";
+        verticalBottom.style.position = "absolute";
+        verticalBottom.style.backgroundColor = "#fff";
+        verticalBottom.style.zIndex = "522";
+        verticalBottom.style.opacity = "0.5";
+        //左上边线
+        let LeftTopSide = document.createElement("div");
+        LeftTopSide.style.width = "30px";
+        LeftTopSide.style.height = "4px";
+        LeftTopSide.style.top = "-4px";
+        LeftTopSide.style.left = "-4px";
+        LeftTopSide.style.position = "absolute";
+        LeftTopSide.style.backgroundColor = "#fff";
+        LeftTopSide.style.zIndex = "522";
+        LeftTopSide.style.opacity = "1";
+        //上左边线
+        let TopListSide = document.createElement("div");
+        TopListSide.style.width = "4px";
+        TopListSide.style.height = "30px";
+        TopListSide.style.top = "-4px";
+        TopListSide.style.left = "-4px";
+        TopListSide.style.position = "absolute";
+        TopListSide.style.backgroundColor = "#fff";
+        TopListSide.style.zIndex = "522";
+        TopListSide.style.opacity = "1";
+        //右上边线
+        let RightTopSide = document.createElement("div");
+        RightTopSide.style.width = "30px";
+        RightTopSide.style.height = "4px";
+        RightTopSide.style.top = "-4px";
+        RightTopSide.style.right = "-4px";
+        RightTopSide.style.position = "absolute";
+        RightTopSide.style.backgroundColor = "#fff";
+        RightTopSide.style.zIndex = "522";
+        RightTopSide.style.opacity = "1";
+        //上右边线
+        let TopRightSide = document.createElement("div");
+        TopRightSide.style.width = "4px";
+        TopRightSide.style.height = "30px";
+        TopRightSide.style.top = "-4px";
+        TopRightSide.style.right = "-4px";
+        TopRightSide.style.position = "absolute";
+        TopRightSide.style.backgroundColor = "#fff";
+        TopRightSide.style.zIndex = "522";
+        TopRightSide.style.opacity = "1";
+        //左下边线
+        let LeftBottomSide = document.createElement("div");
+        LeftBottomSide.style.width = "30px";
+        LeftBottomSide.style.height = "4px";
+        LeftBottomSide.style.bottom = "-4px";
+        LeftBottomSide.style.left = "-4px";
+        LeftBottomSide.style.position = "absolute";
+        LeftBottomSide.style.backgroundColor = "#fff";
+        LeftBottomSide.style.zIndex = "522";
+        LeftBottomSide.style.opacity = "1";
+        //下左边线
+        let BottomListSide = document.createElement("div");
+        BottomListSide.style.width = "4px";
+        BottomListSide.style.height = "30px";
+        BottomListSide.style.bottom = "-4px";
+        BottomListSide.style.left = "-4px";
+        BottomListSide.style.position = "absolute";
+        BottomListSide.style.backgroundColor = "#fff";
+        BottomListSide.style.zIndex = "522";
+        BottomListSide.style.opacity = "1";
+        //右下边线
+        let RightBottomSide = document.createElement("div");
+        RightBottomSide.style.width = "30px";
+        RightBottomSide.style.height = "4px";
+        RightBottomSide.style.bottom = "-4px";
+        RightBottomSide.style.right = "-4px";
+        RightBottomSide.style.position = "absolute";
+        RightBottomSide.style.backgroundColor = "#fff";
+        RightBottomSide.style.zIndex = "522";
+        RightBottomSide.style.opacity = "1";
+        //下右边线
+        let BottomRightSide = document.createElement("div");
+        BottomRightSide.style.width = "4px";
+        BottomRightSide.style.height = "30px";
+        BottomRightSide.style.bottom = "-4px";
+        BottomRightSide.style.right = "-4px";
+        BottomRightSide.style.position = "absolute";
+        BottomRightSide.style.backgroundColor = "#fff";
+        BottomRightSide.style.zIndex = "522";
+        BottomRightSide.style.opacity = "1";
+        //一起生成
+        box.appendChild(verticalLeft);
+        box.appendChild(verticalRight);
+        box.appendChild(verticalTop);
+        box.appendChild(verticalBottom);
+        box.appendChild(LeftTopSide);
+        box.appendChild(TopListSide);
+        box.appendChild(RightTopSide);
+        box.appendChild(TopRightSide);
+        box.appendChild(LeftBottomSide);
+        box.appendChild(BottomListSide);
+        box.appendChild(RightBottomSide);
+        box.appendChild(BottomRightSide);
+      }
+    },
+    //异步onload图片
+    onLoadImg(photoUrl: any) {
+      return new Promise(function(resolve, reject) {
+        let reader = new FileReader();
+        reader.readAsDataURL(photoUrl);
+        reader.onload = (e: any) => {
+          resolve(e.target["result"]);
+        };
+      });
+    },
+    /**
+     * 载入文件
+     * template:
+     *    <h5-cropper hide-input ref="cropper">
+     *
+     * javascript:
+     *    this.$refs.cropper.loadFile()
+     *
+     * @param file
+     */
+    loadFile(file: any) {
+      if (file instanceof File) {
+        this.onLoadImg(file).then((base64: any) => {
+          this.img = base64;
+          setTimeout(() => {
+            this.config.autoCrop = true;
+            this.addSlide();
+          }, 10);
+        });
+      } else {
+        throw new Error("Arguments file is not File");
+      }
+    },
+    /**
+     *
+     * @param base64
+     */
+    loadBase64(base64: string) {
+      if (typeof base64 !== "string") {
+        throw new Error("Arguments base64 is not string");
+      }
+      const base = base64.split(",");
+      if (!/^data:image\/(.*?);base64$/.test(base[0])) {
+        throw new Error("Arguments base64 MIME is not image/*");
+      }
+      // Base64 Regex @see https://learnku.com/articles/42295
+      if (
+        !/^[\/]?([\da-zA-Z]+[\/+]+)*[\da-zA-Z]+([+=]{1,2}|[\/])?$/.test(base[1])
+      ) {
+        throw new Error("Not standard base64");
+      }
+      this.img = base64;
+      setTimeout(() => {
+        this.config.autoCrop = true;
+        this.addSlide();
+      }, 10);
+    },
+    rotating(e: any) {
+      (this as any).$refs.cropper.rotateRight();
+      // document.getElementsByClassName("cropper-modal")[0].style = "background-color: rgba(0,0,0,0.5);transition: 0.88s";
+    },
+    canceltailor() {
+      this.img = ""
+      this.onCancelTailor()
+    },
+    tailoring() {
+      // 获取截图的base64数据
+      (this as any).$refs.cropper.getCropData((data: any) => {
+        this.getBase64Data(data);
+        this.getBlob(data);
+        this.img = "";
+        this.config.autoCrop = false;
+      });
+      // 获取截图的blob数据
+      (this as any).$refs.cropper.getCropBlob((data: BlobPart) => {
+        this.getBase64Data(data);
+        this.getBlob(data);
+        // Blob 转 File
+        const suffix = {
+          jpeg: "jpg",
+          png: "png",
+          webp: "webp"
+        }[this.config.outputType];
+        const time = new Date().getTime();
+        const file = new File([data], `${time}.${suffix}`, {
+          type: `image/${this.config.outputType}`
+        });
+        this.getFile(file);
+        this.img = "";
+        this.config.autoCrop = false;
+      });
+    },
+    async upPhoto(e: any) {
+      let photoUrl = e.target.files[0];
+      (this as any).$refs.headInput.value = null;
+      if (photoUrl != undefined) {
+        this.imgOriginF(photoUrl);
+        this.img = await this.onLoadImg(photoUrl) as string;
+        this.config.autoCrop = true;
+        setTimeout(() => {
+          this.addSlide();
+        }, 20);
+      }
+    },
+    onCropMoving(e: any) {
+      // console.log('onCropMoving')
+    },
+    onImgMoving(e: any) {
+      // console.log('onCropMoving')
+    },
+  },
+  render() {
+    return (
+      <div class={styles.upbtn}>
+        {this.hideInput}
+        {!this.hideInput ? <input
+          style="opacity: 0;"
+          class={styles.upbtn}
+          type="file"
+          accept="image/*"
+          onChange={this.upPhoto}
+          ref="headInput"
+        /> : null}
+        {this.img != '' ? <div class={styles.bg}>
+          {!this.config.ceilbutton ? <div class={styles.btndiv}>
+            <div class={styles.btn} onClick={this.canceltailor} style={{
+              backgroundColor: this.config.cancelButtonBackgroundColor,
+              color: this.config.cancelButtonTextColor
+            }}>{ this.config.cancelButtonText }</div>
+            <div class={styles.img} onClick={this.rotating}></div>
+            <div class={styles.btn} onClick={this.tailoring} style={{
+              backgroundColor: this.config.confirmButtonBackgroundColor,
+              color: this.config.confirmButtonTextColor
+            }}>{ this.config.confirmButtonText }</div>
+          </div> : null}
+
+          <div class={styles.wrapper}>
+            <VueCropper
+              ref="cropper"
+              img={this.img}
+              outputSize={this.config.outputSize}
+              outputType={this.config.outputType}
+              info={this.config.info}
+              canScale={this.config.canScale}
+              autoCrop={this.config.autoCrop}
+              autoCropWidth={this.config.autoCropWidth}
+              autoCropHeight={this.config.autoCropHeight}
+              fixedBox={this.config.fixedBox}
+              fixed={this.config.fixed}
+              fixedNumber={this.config.fixedNumber}
+              full={this.config.full}
+              canMove={this.config.canMove}
+              canMoveBox={this.config.canMoveBox}
+              original={this.config.original}
+              centerBox={this.config.centerBox}
+              high={this.config.high}
+              infoTrue={this.config.infoTrue}
+              maxImgSize={this.config.maxImgSize}
+              enlarge={this.config.enlarge}
+              mode={this.config.mode}
+              onCropMoving={this.onCropMoving}
+              onImgMoving={this.onImgMoving}
+            ></VueCropper>
+          </div>
+
+          {!this.config.ceilbutton ? <div class={styles.btndiv}>
+            <div class={styles.btn} onClick={this.canceltailor} style={{
+              backgroundColor: this.config.cancelButtonBackgroundColor,
+              color: this.config.cancelButtonTextColor
+            }}>{this.config.cancelButtonText}</div>
+            <div class={styles.img} onClick={this.rotating}></div>
+            <div class={styles.btn} onClick={this.tailoring} style={{
+              backgroundColor: this.config.confirmButtonBackgroundColor,
+              color: this.config.confirmButtonTextColor
+            }}>{this.config.confirmButtonText}</div>
+          </div> : null }
+        </div> : null }
+      </div>
+    )
+  }
+})

+ 15 - 7
src/components/col-upload/index.tsx

@@ -1,7 +1,7 @@
 import { Icon, Image, Toast, Uploader } from "vant";
 import { defineComponent } from "vue";
-import vueCropper from 'vue-cropper';
 import styles from "./index.module.less";
+import ColCropper from "../col-cropper";
 
 import iconUploader from '@common/images/icon_uploader.png';
 import request from "@/helpers/request";
@@ -57,16 +57,24 @@ export default defineComponent({
       this.$emit('update:value', null);
       e.stopPropagation();
     },
+    async getFile(file: any) {
+      // 上传文件
+      try {
+        let formData = new FormData();
+        formData.append('file', file);
+        let res = await request.post('/api-teacher/uploadFile', {
+          data: formData
+        })
+        this.$emit('update:value', res.data.url);
+      } catch {
+        //
+      }
+    }
   },
   render() {
     return (
       <div class={styles['uploader-section']}>
-        {this.cropper ? <vueCropper
-          ref="cropper"
-          img="option.img"
-          outputSize="option.size"
-          outputType="option.outputType"
-        ></vueCropper> : (
+        {this.cropper ? <ColCropper getFile={this.getFile} /> : (
           // @ts-ignore
           <Uploader afterRead={this.afterRead} beforeRead={this.beforeRead} beforeDelete={this.beforeDelete}
             v-slots={{

+ 1 - 1
src/student/layout/auth.module.less

@@ -3,7 +3,7 @@
   display: flex;
   padding-top: 20px;
   flex-direction: column;
-  min-height: 100vh;
+  min-height: calc(100vh - 20px);
   align-items: center;
   justify-content: center;
   .info {

+ 17 - 3
src/student/practice-class/index.tsx

@@ -1,18 +1,32 @@
 import { defineComponent } from "vue";
 import styles from './index.module.less';
 import ColHeader from '@/components/col-header';
-import { Sticky } from "vant";
+import { Button, Sticky } from "vant";
+import ColCropper from "@/components/col-cropper";
+import ColUpload from "@/components/col-upload";
 
 export default defineComponent({
   name: "practiceClass",
+  methods: {
+    getFile(_file: any) {
+      console.log(_file)
+    }
+  },
   render() {
     return (
       <>
-        <Sticky>
+        {/* <Sticky>
           <ColHeader title="陪练课" isFixed={false} isBack background="green">
             显示
           </ColHeader>
-        </Sticky>
+        </Sticky> */}
+        <div class={styles.practiceClass}>
+          <div>
+            <Button>添加<ColCropper getFile={() => this.getFile} /></Button>
+          </div>
+
+          <ColUpload cropper />
+        </div>
       </>
     )
   }

+ 1 - 1
src/teacher/layout/auth.module.less

@@ -3,7 +3,7 @@
   display: flex;
   padding-top: 20px;
   flex-direction: column;
-  min-height: 100vh;
+  min-height: calc(100vh - 20px);
   align-items: center;
   justify-content: center;
   .info {

+ 1 - 1
tsconfig.json

@@ -31,7 +31,7 @@
     "src/**/*.d.ts",
     "src/**/*.tsx",
     "src/**/*.vue"
-  ],
+, "src/components/col-cropper/index.tsx1"  ],
   "exclude": [
     "node_modules",
     "dist"

Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff