二维码识别

import React, { useState, useRef } from 'react';
import { QrcodeOutlined } from '@ant-design/icons';
import '@ant-design/compatible/assets/index.css';
import { Modal, Button, message } from 'antd';
import { useObserver } from 'mobx-react';
import { useHistory, useLocation } from 'react-router-dom';
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
import QrCode from 'qrcode-reader';
import jsQR from 'jsqr';
import ajax from '@/lib/axios';
import { Wrapper, SuccessWrapper, UploadImgWrapper } from './link-qrcode-style';

interface IProps {
  merchantId: string;
  branchName: string;
  merchantName: string;
  personInCharge: string;
}

const LinkQrCode = (props: IProps) => {
  const qr = new QrCode();
  const [showConfirmModal, setShowConfirmModal] = useState<boolean>(false);
  const [showSuccessModal, setShowSuccessModal] = useState<boolean>(false);
  const [showUploadModal, setShowUploadModal] = useState<boolean>(false);
  const [uploadButtonLoading, setUploadButtonLoading] = useState<boolean>(false);
  const [confirmButtonLoading, setConfirmButtonLoading] = useState<boolean>(false);
  const [qrCodeUrl, setQrCodeUrl] = useState<string>('');
  const [qrDecode, setQrDecode] = useState<string>('');
  const [uploadImgUrl, setUploadImgUrl] = useState<string>('');
  const [uploadImgFile, setUploadImgFile] = useState<object>({});
  const history = useHistory();
  const location = useLocation();
  const fileInputRef = useRef<HTMLInputElement>(null);
  // const ua = navigator.userAgent.toLowerCase();
  // const isIos = ua.indexOf('iphone') !== -1 || ua.indexOf('ipad') !== -1;

  const backToListPage = () => {
    const to = `${location.pathname}${location.search}`;
    history.push(to);
  };

  const getFileUrl = (file: object) => {
    if (file === undefined) return;
    let url = null;
    if ((window as any).createObjectURL != undefined) {
      // basic
      url = (window as any).createObjectURL(file);
    } else if (window.URL != undefined) {
      // mozilla(firefox)
      url = window.URL.createObjectURL(file);
    } else if (window.webkitURL != undefined) {
      // webkit or chrome
      url = window.webkitURL.createObjectURL(file);
    }
    return url;
  };

  const getQrCode = () => {
    console.log('beibei111', uploadImgFile);
    qr.decode(uploadImgUrl);
    qr.callback = async function(error: any, resCode: any) {
      if (error) {
        Modal.error({
          content: error,
        });
        return;
      }
      const decodeArr = resCode.result.split('/');
      const cutQrDecode = decodeArr[decodeArr.length - 1];
      console.log('beibei1113333', resCode.result, cutQrDecode, uploadImgFile);
      setQrDecode(cutQrDecode);
      // 请求后端接口进行解析
      try {
        const {
          data: { data },
        } = await ajax.get(`/qrcode/validate/${cutQrDecode}`);
        console.log('beibei 是否有效', data);
        setUploadButtonLoading(false);
        setShowUploadModal(false);
        if (data) {
          setShowConfirmModal(true);
        } else {
          Modal.error({
            content: "Sorry, we can't process this picture, please make sure you use a clear picture of valid QR code.",
            onOk() {
              const to = `${location.pathname}${location.search}`;
              history.push(to);
            },
          });
        }
      } catch (e) {
        message.error(e.message);
      }
    };
  };

  const handleLinkButton = (e: React.MouseEvent) => {
    e.preventDefault();
    if (!!fileInputRef) {
      (fileInputRef as any).current.click();
    }
  };

  const handleFileChange = (e: any) => {
    const files = e.target.files;
    if (files[0] !== undefined) {
      const fr = new FileReader();
      fr.readAsDataURL(files[0]);
      fr.addEventListener('load', () => {
        setUploadImgUrl(fr.result as string);
        setUploadImgFile(files[0]);
        setShowUploadModal(true);
        // qrCodeUploadedHandler(fr.result as string);
        drawImg(files[0]);
      });
    } else {
      setUploadImgUrl('');
      setUploadImgFile({});
    }
  };

  const drawImg = (file: any) => {
    createImageBitmap(file).then(bmp => {
      const canvas = document.createElement('canvas');

      const width: number = bmp.width;
      const height: number = bmp.height;
      canvas.width = bmp.width;
      canvas.height = bmp.height;

      const ctx = canvas.getContext('2d') as any;

      ctx.drawImage(bmp, 0, 0);
      const qrCodeImageFormat = ctx.getImageData(0, 0, bmp.width, bmp.height);
      const qrDecoded = jsQR(qrCodeImageFormat.data, qrCodeImageFormat.width, qrCodeImageFormat.height);
      alert(qrDecoded.data);
      console.log('beibeicccmmmmm', qrCodeImageFormat, qrDecoded);
    });
  };

  const qrCodeUploadedHandler = (fileImageUrl: string) => {
    const img = new Image();
    // img.src = fileImageUrl;
    img.onload = () => {
      const canvas = document.createElement('canvas');
      const originWidth = img.width;
      const originHeight = img.height;
      // const maxWidth = 1600;
      // const maxHeight = 1200;
      // let targetWidth = originWidth;
      // let targetHeight = originHeight;
      // if (originWidth > maxWidth || originHeight > maxHeight) {
      //   if (originWidth / originHeight > maxWidth / maxHeight) {
      //     // 更宽,按照宽度限定尺寸
      //     targetWidth = maxWidth;
      //     targetHeight = Math.round(maxWidth * (originHeight / originWidth));
      //   } else {
      //     targetHeight = maxHeight;
      //     targetWidth = Math.round(maxHeight * (originWidth / originHeight));
      //   }
      // };
      // canvas对图片进行缩放
      canvas.width = originWidth;
      canvas.height = originHeight;
      const context = canvas.getContext('2d') as any;
      // 清除画布
      // context.clearRect(0, 0, targetWidth, targetHeight);
      // 图片压缩
      context.drawImage(img, 0, 0);
      const imageData = context.getImageData(0, 0, canvas.width, canvas.height);
      const code = jsQR(imageData.data, imageData.width, imageData.height);
      console.log('beibeiccc222', imageData, code);
      canvas.remove();
    };
    img.onerror = () => console.error('Upload file of image format please.');
    img.src = fileImageUrl;
  };

  const handleUploadButton = (e: React.MouseEvent) => {
    e.preventDefault();
    setUploadButtonLoading(true);
    getQrCode();
  };

  const handleConfirmLink = async (e: React.MouseEvent) => {
    e.preventDefault();
    setConfirmButtonLoading(true);
    try {
      const {
        data: { data },
      } = await ajax.post('/qrcode/bind', { qrcode: qrDecode, bindObjectId: props.merchantId });
      if (data.length > 0) {
        setQrCodeUrl(data[0]);
        setConfirmButtonLoading(false);
        setShowConfirmModal(false);
        setShowSuccessModal(true);
      }
    } catch (e) {
      message.error(e.message);
    }
  };

  const handleConfirmModalCancel = (e: React.MouseEvent) => {
    e.preventDefault();
    setShowConfirmModal(false);
    backToListPage();
  };

  const handleSuccessModalCancel = (e: React.MouseEvent) => {
    e.preventDefault();
    setShowSuccessModal(false);
    backToListPage();
  };

  return useObserver(() => (
    <>
      <div>
        <Button onClick={handleLinkButton} style={{ width: '100%', marginTop: 5 }} type="default" size="small">
          <QrcodeOutlined />
          Link QR code
        </Button>
        <input
          type="file"
          name="cover"
          accept="image/*"
          ref={fileInputRef}
          style={{ width: 0, height: 0 }}
          onChange={handleFileChange}
        />
      </div>
      <Modal
        destroyOnClose={true}
        title="Confirm Information"
        visible={showConfirmModal}
        style={{ top: 20 }}
        width={'50%'}
        maskClosable={false}
        footer={[
          <Button
            type="primary"
            key="confirm"
            loading={confirmButtonLoading}
            htmlType="button"
            onClick={handleConfirmLink}>
            Confirm
          </Button>,
          <Button key="cancel" htmlType="button" onClick={handleConfirmModalCancel}>
            Cancel
          </Button>,
        ]}
        onCancel={handleConfirmModalCancel}>
        <Wrapper>
          <p>
            {/* eslint-disable-next-line react/no-unescaped-entities */}
            You're linking the QR code you scaned to the following merchant. Please check the merchant information
            throughly.
          </p>
          <div className="confirm-information">
            <div className="confirm-information-item">
              <span>Merchant ID:</span>
              <p>{props.merchantId}</p>
            </div>
            <div className="confirm-information-item">
              <span>Branch Name:</span>
              <p>{props.branchName}</p>
            </div>
            <div className="confirm-information-item">
              <span>Merchant Name:</span>
              <p>{props.merchantName}</p>
            </div>
            <div className="confirm-information-item">
              <span>Person in Charge:</span>
              <p>{props.personInCharge}</p>
            </div>
          </div>
        </Wrapper>
      </Modal>
      <Modal
        destroyOnClose={true}
        visible={showSuccessModal}
        style={{ top: 20 }}
        width={'50%'}
        maskClosable={false}
        footer={null}
        onCancel={handleSuccessModalCancel}>
        <SuccessWrapper>
          <p className="top-tip">QR code has been successfully linked!</p>
          <div className="branch-name">
            <span>Branch Name:</span>
            <p>{props.branchName}</p>
          </div>
          <div className="qr-code">
            <span>QR Code:</span>
            <img src={qrCodeUrl} alt="图片加载失败" />
          </div>
        </SuccessWrapper>
      </Modal>
      <Modal
        destroyOnClose={true}
        visible={showUploadModal}
        style={{ top: 20, textAlign: 'center' }}
        width={'50%'}
        maskClosable={false}
        closable={false}
        footer={null}>
        <UploadImgWrapper>
          <img src={uploadImgUrl} style={{ maxWidth: '400px' }} alt="" />
        </UploadImgWrapper>
        <Button
          type="primary"
          key="confirm"
          loading={uploadButtonLoading}
          size="large"
          htmlType="button"
          style={{ margin: '20px' }}
          onClick={handleUploadButton}>
          UPLOAD
        </Button>
      </Modal>
    </>
  ));
};

export default LinkQrCode;

 

 

 

 

 

 

 

扫描方案如下:

import React, { useState, useRef } from 'react';
import { QrcodeOutlined } from '@ant-design/icons';
import '@ant-design/compatible/assets/index.css';
import { Modal, Button, message } from 'antd';
import { useObserver } from 'mobx-react';
import { useHistory, useLocation } from 'react-router-dom';
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
import QrCode from 'qrcode-reader';
import jsQR from 'jsqr';
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
import QrReader from 'react-qr-reader';
import ajax from '@/lib/axios';
import { Wrapper, SuccessWrapper, UploadImgWrapper } from './link-qrcode-style';

interface IProps {
  merchantId: string;
  branchName: string;
  merchantName: string;
  personInCharge: string;
}

const LinkQrCode = (props: IProps) => {
  const qr = new QrCode();
  const [showConfirmModal, setShowConfirmModal] = useState<boolean>(false);
  const [showSuccessModal, setShowSuccessModal] = useState<boolean>(false);
  const [showUploadModal, setShowUploadModal] = useState<boolean>(false);
  const [uploadButtonLoading, setUploadButtonLoading] = useState<boolean>(false);
  const [confirmButtonLoading, setConfirmButtonLoading] = useState<boolean>(false);
  const [qrCodeUrl, setQrCodeUrl] = useState<string>('');
  const [qrDecode, setQrDecode] = useState<string>('');
  const [uploadImgUrl, setUploadImgUrl] = useState<string>('');
  const [uploadImgFile, setUploadImgFile] = useState<object>({});
  const history = useHistory();
  const location = useLocation();
  const fileInputRef = useRef<HTMLInputElement>(null);
  // const ua = navigator.userAgent.toLowerCase();
  // const isIos = ua.indexOf('iphone') !== -1 || ua.indexOf('ipad') !== -1;

  const backToListPage = () => {
    const to = `${location.pathname}${location.search}`;
    history.push(to);
  };

  // const getFileUrl = (file: object) => {
  //   if (file === undefined) return;
  //   let url = null;
  //   if ((window as any).createObjectURL != undefined) {
  //     // basic
  //     url = (window as any).createObjectURL(file);
  //   } else if (window.URL != undefined) {
  //     // mozilla(firefox)
  //     url = window.URL.createObjectURL(file);
  //   } else if (window.webkitURL != undefined) {
  //     // webkit or chrome
  //     url = window.webkitURL.createObjectURL(file);
  //   }
  //   return url;
  // };

  const getQrCode = () => {
    console.log('beibei111', uploadImgFile);
    qr.decode(uploadImgUrl);
    qr.callback = async function(error: any, resCode: any) {
      if (error) {
        Modal.error({
          content: error,
        });
        return;
      }
      const decodeArr = resCode.result.split('/');
      const cutQrDecode = decodeArr[decodeArr.length - 1];
      console.log('beibei1113333', resCode.result, cutQrDecode, uploadImgFile);
      setQrDecode(cutQrDecode);
      // 请求后端接口进行解析
      try {
        const {
          data: { data },
        } = await ajax.get(`/qrcode/validate/${cutQrDecode}`);
        console.log('beibei 是否有效', data);
        setUploadButtonLoading(false);
        setShowUploadModal(false);
        if (data) {
          setShowConfirmModal(true);
        } else {
          Modal.error({
            content: "Sorry, we can't process this picture, please make sure you use a clear picture of valid QR code.",
            onOk() {
              const to = `${location.pathname}${location.search}`;
              history.push(to);
            },
          });
        }
      } catch (e) {
        message.error(e.message);
      }
    };
  };

  const handleLinkButton = (e: React.MouseEvent) => {
    e.preventDefault();
    // if (!!fileInputRef) {
    //   (fileInputRef as any).current.click();
    // }
    setShowUploadModal(true);
    // setTimeout(scanQrCode, 2000);
  };

  const scanQrCode = () => {
    const video = document.createElement('video');
    const canvasElement = document.getElementById('canvas');
    const canvas = canvasElement.getContext('2d') as any;
    const loadingMessage = document.getElementById("loadingMessage");
    function drawLine(begin, end, color) {
      canvas.beginPath();
      canvas.moveTo(begin.x, begin.y);
      canvas.lineTo(end.x, end.y);
      canvas.lineWidth = 4;
      canvas.strokeStyle = color;
      canvas.stroke();
    }
    // Use facingMode: environment to attemt to get the front camera on phones
    navigator.mediaDevices.getUserMedia({ video: { facingMode: "environment" } }).then(function(stream) {
      video.srcObject = stream;
      video.setAttribute('playsinline', true); // required to tell iOS safari we don't want fullscreen
      video.play();
      requestAnimationFrame(tick);
    });
    function tick() {
      loadingMessage.innerText = "⌛ Loading video..."
      if (video.readyState === video.HAVE_ENOUGH_DATA) {
        loadingMessage.hidden = true;
        canvasElement.hidden = false;

        canvasElement.height = video.videoHeight;
        canvasElement.width = video.videoWidth;
        canvas.drawImage(video, 0, 0, canvasElement.width, canvasElement.height);
        const imageData = canvas.getImageData(0, 0, canvasElement.width, canvasElement.height);
        const code = jsQR(imageData.data, imageData.width, imageData.height, {
          inversionAttempts: "dontInvert",
        });
        if (code) {
          drawLine(code.location.topLeftCorner, code.location.topRightCorner, "#FF3B58");
          drawLine(code.location.topRightCorner, code.location.bottomRightCorner, "#FF3B58");
          drawLine(code.location.bottomRightCorner, code.location.bottomLeftCorner, "#FF3B58");
          drawLine(code.location.bottomLeftCorner, code.location.topLeftCorner, "#FF3B58");
          console.log('beibei1111', code.data)
        } else {
        }
      }
      requestAnimationFrame(tick);
    }
  };

  const handleFileChange = (e: any) => {
    const files = e.target.files;
    if (files[0] !== undefined) {
      const fr = new FileReader();
      fr.readAsDataURL(files[0]);
      fr.addEventListener('load', () => {
        setUploadImgUrl(fr.result as string);
        setUploadImgFile(files[0]);
        setShowUploadModal(true);
        // qrCodeUploadedHandler(fr.result as string);
      });
    } else {
      setUploadImgUrl('');
      setUploadImgFile({});
    }
  };

  const handleUploadButton = (e: React.MouseEvent) => {
    e.preventDefault();
    setUploadButtonLoading(true);
    getQrCode();
  };

  const handleConfirmLink = async (e: React.MouseEvent) => {
    e.preventDefault();
    setConfirmButtonLoading(true);
    try {
      const {
        data: { data },
      } = await ajax.post('/qrcode/bind', { qrcode: qrDecode, bindObjectId: props.merchantId });
      if (data.length > 0) {
        setQrCodeUrl(data[0]);
        setConfirmButtonLoading(false);
        setShowConfirmModal(false);
        setShowSuccessModal(true);
      }
    } catch (e) {
      message.error(e.message);
    }
  };

  const handleConfirmModalCancel = (e: React.MouseEvent) => {
    e.preventDefault();
    setShowConfirmModal(false);
    backToListPage();
  };

  const handleSuccessModalCancel = (e: React.MouseEvent) => {
    e.preventDefault();
    setShowSuccessModal(false);
    backToListPage();
  };

  const handleScan = (result: any) => {
    if (result) {
      console.log('beibei0000', result);
    }
  };
  const handleError = (err: any) => {
    console.error('beibei' + err);
  };
  const openImageDialog = () => {
    // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
    // @ts-ignore
    fileInputRef.current.openImageDialog();
  };

  return useObserver(() => (
    <>
      <div>
        <Button onClick={handleLinkButton} style={{ width: '100%', marginTop: 5 }} type="default" size="small">
          <QrcodeOutlined />
          Link QR code
        </Button>
        <input
          type="file"
          name="cover"
          accept="image/*"
          ref={fileInputRef}
          style={{ width: 0, height: 0 }}
          onChange={handleFileChange}
        />
      </div>
      <Modal
        destroyOnClose={true}
        title="Confirm Information"
        visible={showConfirmModal}
        style={{ top: 20 }}
        width={'50%'}
        maskClosable={false}
        footer={[
          <Button
            type="primary"
            key="confirm"
            loading={confirmButtonLoading}
            htmlType="button"
            onClick={handleConfirmLink}>
            Confirm
          </Button>,
          <Button key="cancel" htmlType="button" onClick={handleConfirmModalCancel}>
            Cancel
          </Button>,
        ]}
        onCancel={handleConfirmModalCancel}>
        <Wrapper>
          <p>
            {/* eslint-disable-next-line react/no-unescaped-entities */}
            You're linking the QR code you scaned to the following merchant. Please check the merchant information
            throughly.
          </p>
          <div className="confirm-information">
            <div className="confirm-information-item">
              <span>Merchant ID:</span>
              <p>{props.merchantId}</p>
            </div>
            <div className="confirm-information-item">
              <span>Branch Name:</span>
              <p>{props.branchName}</p>
            </div>
            <div className="confirm-information-item">
              <span>Merchant Name:</span>
              <p>{props.merchantName}</p>
            </div>
            <div className="confirm-information-item">
              <span>Person in Charge:</span>
              <p>{props.personInCharge}</p>
            </div>
          </div>
        </Wrapper>
      </Modal>
      <Modal
        destroyOnClose={true}
        visible={showSuccessModal}
        style={{ top: 20 }}
        width={'50%'}
        maskClosable={false}
        footer={null}
        onCancel={handleSuccessModalCancel}>
        <SuccessWrapper>
          <p className="top-tip">QR code has been successfully linked!</p>
          <div className="branch-name">
            <span>Branch Name:</span>
            <p>{props.branchName}</p>
          </div>
          <div className="qr-code">
            <span>QR Code:</span>
            <img src={qrCodeUrl} alt="图片加载失败" />
          </div>
        </SuccessWrapper>
      </Modal>
      <Modal
        destroyOnClose={true}
        visible={showUploadModal}
        style={{ top: 20, textAlign: 'center' }}
        width={'50%'}
        maskClosable={false}
        closable={false}
        footer={null}>
        {/*<UploadImgWrapper>*/}
        {/*  <img src={uploadImgUrl} style={{ maxWidth: '400px' }} alt="" />*/}
        {/*</UploadImgWrapper>*/}
        {/*<div id="loadingMessage">🎥 Unable to access video stream (please make sure you have a webcam enabled)</div>*/}
        {/*<canvas id="canvas" style={{ maxWidth: '640px' }} hidden/>*/}
        <QrReader
          ref={fileInputRef}
          delay={100}
          style={{ maxWidth: '640px' }}
          onError={handleError}
          onScan={handleScan}
        />
        <input type="button" value="Submit QR Code" onClick={openImageDialog} />
        <Button
          type="primary"
          key="confirm"
          loading={uploadButtonLoading}
          size="large"
          htmlType="button"
          style={{ margin: '20px' }}
          onClick={handleUploadButton}>
          UPLOAD
        </Button>
      </Modal>
    </>
  ));
};

export default LinkQrCode;

 

posted @ 2020-03-19 19:01  贝子涵夕  阅读(337)  评论(0)    收藏  举报