js(vue)如何实现页面截图,向后端传递,生成PDF

利用 htmm12canvas

首先引入

npm install express multer
# 或者
yarn add express multer

代码如下:

<template>
  <!-- <div style="width:100%;height:100%;overflow-y: scroll">
    <img :src="svg" style="width: 100%;" />
  </div> -->
  <div class="backScreen">
    中间代码省略
  </div>
</template>

<script setup>

import { nextTick, ref, provide } from "vue";
import { useGetResizeBodySize } from '@/hooks/useGetScaleHeight'

import EquConsumeSpareRank from './charts/EquConsumeSpareRank'
import EquPurchaseSpareRank from './charts/EquPurchaseSpareRank'
import SpareConsumeRank from './charts/SpareConsumeRank'
import SpareOverView from './charts/SpareOverView'
import StoreAvgDurationRank from './charts/StoreAvgDurationRank'
import StoreInactive from './charts/StoreInactive'

import img169 from './imgs/dp_16.9.svg'
import img1610 from './imgs/dp_16.10.svg'
import html2canvas from 'html2canvas';




const imageWidth = ref('100%')
const imageHeight = ref('100%')
const backImg = ref(img169)
const fullScreen = ref(false)
const margin = ref(0)

provide('screenHeight', imageHeight)

useGetResizeBodySize(e => {
  const { screenWidth, screenHeight } = e
  imageWidth.value = screenWidth
  imageHeight.value = screenHeight
  console.log('imageHeight.value', imageHeight.value)
  // 上下的margin
  margin.value = imageHeight.value * 0.02
  // console.log('outer', window.outerWidth, window.outerHeight, screenWidth, screenHeight)
  const ratio = screenWidth/screenHeight
  if (ratio === 16/9 || ratio === 16/10) {
    fullScreen.value = true
  }
  if (ratio === 16/10) {
    backImg.value = img1610
  }else {
    backImg.value = img169
  }

})

// 定义截图和发送截图的方法   下面是关键代码
const captureScreen = async () => {
  return new Promise((resolve, reject) => {
    nextTick(() => {
      html2canvas(document.querySelector('.backScreen'), {
        logging: false,
        scale: 2,
        useCORS: true,
      }).then(canvas => {
        canvas.toBlob(blob => resolve(blob), 'image/png');
      }).catch(err => reject(err));
    });
  });
};

const sendToServer = async (blob) => {
  try {
    const formData = new FormData();
    formData.append('image', blob, 'screenshot.png');
    console.log("发送图片给后台")
    const response = await fetch('http://127.0.0.1:8081/test/upload-image', {
      method: 'POST',
      body: formData,
    });

    if (!response.ok) {
      throw new Error(`HTTP error! Status: ${response.status}`);
    }

    const data = await response.json();
    console.log(data);
  } catch (error) {
    console.error('Failed to send screenshot:', error);
  }
};

// 监听键盘事件
const handleKeyPress = (event) => {
  // 检查是否按下了 "O" 键
  if (event.key === 'o' || event.keyCode === 79) {
    console.log("O键被按下")
    event.preventDefault(); // 防止默认行为
    captureScreen().then(blob => {
      sendToServer(blob);
    }).catch(error => {
      console.error('Error capturing screen:', error);
    });
  }
};

// 在组件挂载后添加键盘事件监听器
onMounted(() => {
  document.addEventListener('keydown', handleKeyPress);

  // 清除引用以防止内存泄漏
  onUnmounted(() => {
    document.removeEventListener('keydown', handleKeyPress);
  });
});


</script>

<style lang="scss" scoped>
:deep .el-input__wrapper {
    height: 22px;
    font-size: 10px;
    background-color: #ABD6FF;
    // background-color: transparent;
    /* border: 0px !important; */
    box-shadow: none;
}
.chartRow {
  width: 100%;
  height: 400;
  display: flex;
  justify-content: space-between;
}
.backScreen {
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  // align-items: center;
  position: relative;

  // overflow: auto;
  // background-color: lightgray;
  // background-image: url('./img/bk.svg');
  // background-size: cover;
  // background-clip: border-box;
  // background-repeat: no-repeat;
  .backImg {
    position: absolute;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
  }

  .contentBack {
    // background-color: white;
    // margin: 11% 120px;
    margin-top: 6%;
    margin-left: 6%;
    margin-right: 6%;
    flex: 1;
    z-index: 10;
    height: 82%;

    .card {
      width: 430px;
      height: 100%;
      // height: 370px;
      background-size: 100% 100%;
      background-color: #0241A2;
      border-radius: 20px;
      overflow: hidden;
      display: flex;
      flex-direction: column;
      .card_title {
        width: 100%;
        height: 46px;
        background: linear-gradient(#1187FB, #0241A2);
        border-radius: 20px 20px 0 0;
        padding: 13px 0 0 24px;
        color: #30D9FF
      }
    }

    .cardMax {
      // height: 370px;
      height: 100%;
      background-size: 100% 100%;
      background-color: #0241A2;
      border-radius: 20px;
      display: flex;
      flex-direction: column;
      flex: 1;
      overflow: hidden;
      .cardMax_title {
        width: 100%;
        height: 46px;
        background: linear-gradient(#1187FB, #0241A2);
        border-radius: 20px 20px 0 0;
        padding: 13px 0 0 24px;
        color: #30D9FF
      }
    }
  }

}
</style>

然后是后台很简单的实现,至于生成PDF再说


@RestController
@RequestMapping("test")
@Api(value = "ImageUploadController", tags = "截图导入接口")
public class ImageUploadController {

    @PostMapping("/upload-image")
    public ServiceResponse<String> handleFileUpload(@RequestParam("image") MultipartFile file) {
        if (file.isEmpty()) {
            throw new RuntimeException("文件为空");
        }

        ServiceResponse<String> response = new ServiceResponse<>();

        // 将图片保存到 D:\tu\ 目录下
        String filePath = "D:\\tu\\" + file.getOriginalFilename();
        try {
            file.transferTo(new File(filePath));
            response.setSucess("上传成功");
        } catch (Exception e) {
            response.setError("上传失败");
        }

        return response;
    }
}

如果是针对指定范围的

就在其div加上唯一id

<div id="inactive-store-div" class="chartRow" :style="{'marginTop': margin + 'px', height: (0.4 * imageHeight) + 'px'}">
          <div class="card">
            <div class="card_title">
              <span>设备采购备件排名</span>
            </div>
            <EquPurchaseSpareRank :width="'430'" :height="'260'" @equCountsMfrs="equCountsMfrs"></EquPurchaseSpareRank>
          </div>
          <div class="cardMax" :style="{'margin-left': margin + 'px', 'margin-right': margin + 'px'}">
            <div class="cardMax_title">
              <span>备件消耗量排名</span>
            </div>
            <SpareConsumeRank :width="'800'" :height="'260'" @equCountsMfrs="equCountsMfrs"></SpareConsumeRank>
          </div>
          <div class="card">
            <div class="card_title">
              <span>呆滞库存统计</span>
            </div>
            <StoreInactive :width="'455'" :height="'260'" @equCountsMfrs="equCountsMfrs"></StoreInactive>
          </div>
        </div>

然后这里js改成

const captureScreen = async () => {
  return new Promise((resolve, reject) => {
    nextTick(() => {
      // html2canvas(document.querySelector('.backScreen'), {   //针对全屏
      html2canvas(document.querySelector('#inactive-store-div'), {   //针对指定的范围
      logging: false,
        scale: 2,
        useCORS: true,
      }).then(canvas => {
        canvas.toBlob(blob => resolve(blob), 'image/png');
      }).catch(err => reject(err));
    });
  });
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值