123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246 |
- <template>
- <div class="camera-upload">
- <div class="row">
- <svg-icon icon-class="paizhao" size="80" @click="openMedia" />
- <svg-icon icon-class="bendishangchuan" size="80" @click="selectFile" />
- </div>
- <div class="row">
- <RefreshRight color="#0a59f7" size="70px" @click="clickReset" />
- <Delete color="#ff4d4f" size="60px" @click="clickDeleteAll" />
- </div>
- <input v-show="false" id="fileInput" accept="image/*" type="file" />
- <el-dialog
- id="carmer-dialog"
- v-model="visible"
- :close-on-click-modal="false"
- :title="null"
- close-icon="null"
- width="840px"
- >
- <div v-loading="isLoading">
- <video
- id="video"
- :height="photoSize + 'px'"
- :width="photoSize + 'px'"
- autoplay="autoplay"
- ></video>
- <canvas
- v-show="false"
- id="canvas"
- :height="photoSize + 'px'"
- :width="photoSize + 'px'"
- ></canvas>
- <div class="bottom-btns">
- <el-button class="cancelBtn" @click="closeMedia">关闭</el-button>
- <el-button class="sureBtn" type="primary" @click="takePhoto"
- >拍照
- </el-button>
- </div>
- </div>
- </el-dialog>
- </div>
- </template>
- <script setup>
- import { uploadFileApi } from "@/api/file";
- import { Delete, RefreshRight } from "@element-plus/icons-vue";
- const isLoading = ref(false);
- let mediaStreamTrack = null; // 视频对象(全局)
- let video;
- let photoSize = 800;
- let realSize = 1000;
- const cameraEmit = defineEmits(["uploadFinish", "resetSelect", "deleteAll"]);
- const openMedia = async () => {
- visible.value = true;
- nextTick(() => {
- let constraints = {
- video: { width: photoSize, height: photoSize },
- audio: false,
- };
- //获得video摄像头
- video = document.getElementById("video");
- navigator.mediaDevices
- .getUserMedia(constraints)
- .then((mediaStream) => {
- console.log("mediaStream", mediaStream);
- // mediaStreamTrack = typeof mediaStream.stop === 'function' ? mediaStream : mediaStream.getTracks()[1];
- mediaStreamTrack = mediaStream.getVideoTracks();
- video.srcObject = mediaStream;
- video.play();
- })
- .catch((error) => {
- console.log("Error: " + error);
- ElMessage.error("没有找到设备,或者没有权限");
- });
- });
- };
- function dataURItoBlob(base64Data) {
- var byteString;
- if (base64Data.split(",")[0].indexOf("base64") >= 0)
- byteString = atob(base64Data.split(",")[1]);
- else byteString = unescape(base64Data.split(",")[1]);
- var mimeString = base64Data.split(",")[0].split(":")[1].split(";")[0];
- var ia = new Uint8Array(byteString.length);
- for (var i = 0; i < byteString.length; i++) {
- ia[i] = byteString.charCodeAt(i);
- }
- return new Blob([ia], { type: mimeString });
- }
- // 拍照
- function takePhoto() {
- //获得Canvas对象
- let video = document.getElementById("video");
- let canvas = document.getElementById("canvas");
- canvas.width = realSize; // 实际渲染像素
- canvas.height = realSize; // 实际渲染像素
- let ctx = canvas.getContext("2d");
- ctx.imageSmoothingEnabled = false; //关闭抗锯齿
- ctx.drawImage(video, 0, 0, realSize, realSize);
- isLoading.value = true;
- // toDataURL --- 可传入'image/png'---默认, 'image/jpeg'
- let base64Data = document.getElementById("canvas").toDataURL();
- let blob = dataURItoBlob(base64Data);
- let file = new File([blob], `photo.png`, { type: "image/png" });
- uploadFileApi(file).then((res) => {
- cameraEmit("uploadFinish", res.data.fileUrl);
- isLoading.value = false;
- });
- }
- // 关闭摄像头
- function closeMedia() {
- let stream = document.getElementById("video").srcObject;
- if (stream) {
- let tracks = stream.getTracks();
- tracks?.forEach(function (track) {
- track.stop();
- });
- }
- document.getElementById("video").srcObject = null;
- visible.value = false;
- }
- const visible = ref(false);
- const selectFile = () => {
- let input = document.getElementById("fileInput");
- input.click();
- input.onchange = function () {
- let file = this.files[0];
- console.log(file);
- if (file) {
- uploadFileApi(file).then((res) => {
- cameraEmit("uploadFinish", res.data.fileUrl);
- });
- }
- };
- };
- const clickReset = () => {
- cameraEmit("resetSelect");
- };
- const clickDeleteAll = () => {
- cameraEmit("deleteAll");
- };
- </script>
- <style lang="scss" scoped>
- .camera-upload {
- display: flex;
- flex-direction: column;
- justify-content: space-evenly;
- align-items: center;
- width: 292px;
- height: 292px;
- border-radius: 16px 16px 16px 16px;
- border: 2px dashed rgba(0, 0, 0, 0.2);
- .row {
- width: 100%;
- display: flex;
- justify-content: space-evenly;
- align-items: center;
- }
- .icon-back:nth-child(1) {
- margin-right: 58px;
- }
- }
- </style>
- <style lang="scss" scoped>
- #carmer-dialog {
- background: #f1f3f5;
- box-shadow: 0px 0px 80px 10px rgba(0, 0, 0, 0.25);
- border-radius: 16px 16px 16px 16px;
- width: 924px;
- max-height: 80vh;
- .top-title {
- width: 100%;
- height: 38px;
- font-weight: 500;
- font-size: 38px;
- color: rgba(0, 0, 0, 0.9);
- text-align: center;
- }
- .center-content {
- margin-top: 24px;
- width: 100%;
- //height: 200px;
- display: flex;
- justify-content: center;
- align-items: center;
- font-size: 24px;
- color: rgba(0, 0, 0, 0.9);
- }
- .body {
- width: calc(100% - 240px);
- max-height: calc(50vh - 80px);
- margin: 0 auto;
- overflow-y: auto;
- .box {
- width: 100%;
- height: 100px;
- }
- }
- .bottom-btns {
- display: flex;
- justify-content: center;
- margin-top: 20px;
- margin-bottom: 20px;
- .button {
- margin-right: 20px;
- }
- .cancelBtn {
- width: 292px;
- height: 80px;
- background: rgba(0, 0, 0, 0.06);
- border-radius: 76px 76px 76px 76px;
- }
- .sureBtn {
- width: 292px;
- height: 80px;
- background: #0a59f7;
- border-radius: 76px 76px 76px 76px;
- }
- }
- }
- </style>
|