poster.vue 10.8 KB
<template>
  <div class="poster-page">
    <div @click="goToIndex" style="position: fixed; right: 5px; top: 10px; z-index: 9;">
      <img src="https://cdn.ipadbiz.cn/xfPark/post/public/go-back-btn.1713241695.png" style="width: 2rem; height: 2rem;">
    </div>
    <div class="poster-contain-wrapper">
      <div v-if="flag" style="border: 1.5px solid #9C8882; box-shadow: 8px 8px 8px 0px rgba(156,136,130,1); height: 100%;">
        <div ref="canvasRef" class="poster-contain" style="">
          <div v-if="tree_data?.name" class="poster-text-boxer">
            <div class="poster-text">
              <span class="name">{{ tree_data?.name }}</span>
              <div class="nickname">{{ tree_data?.nickname }}</div>
            </div>
          </div>
          <div style="position: relative;">
            <img :src="imgSrc">
            <div style="position: absolute; right: 5px; bottom: 5px;">
              <img src="https://cdn.ipadbiz.cn/xfPark/post/public/logo.1713241695.png" style=" width: 4rem; height: 5rem;">
            </div>
          </div>
          <div class="poster-mission">
            <div style="font-weight: bold; margin-bottom: 0.5rem;">
              {{ tree_data?.mission_title }}
            </div>
            <div style="font-size: 0.9rem; margin-bottom: 0.5rem;">
              {{ tree_data?.mission_note }}
            </div>
          </div>

        </div>
      </div>
      <div v-if="imgUrl" :style="{border: '1.5px solid #9C8882', boxShadow: '8px 8px 8px 0px rgba(156,136,130,1)', height: ref_height}">
        <img :src="imgUrl" crossOrigin="anonymous" :style="{ width: ref_width, height: ref_height }">
      </div>
    </div>
    <div class="poster-control-wrapper">
      <p class="save-text">长按保存到相册</p>
      <div class="poster-control">
        <div @click="posterPrev" class="poster-prev"></div>
        <van-uploader v-if="tree_data?.is_tree === 1" :before-read="beforeRead" :after-read="afterRead" accept="file">
          <div v-if="!upload_loading" class="poster-upload-btn"></div>
          <van-loading v-else size="24px" color="#fff" text-color="#fff" vertical>上传中...</van-loading>
        </van-uploader>
        <div @click="posterNext" class="poster-next"></div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { v4 as uuidv4 } from 'uuid';
import { qiniuTokenAPI, qiniuUploadAPI, saveFileAPI } from '@/api/common';
import { getTreeAPI, savePosterAPI } from '@/api/carbon.js';
import html2canvas from "html2canvas";
import { showToast } from 'vant';
import { Cookies, $, _, axios, storeToRefs, mainStore, Toast, useTitle } from '@/utils/generatePackage.js'
//import { } from '@/utils/generateModules.js'
//import { } from '@/utils/generateIcons.js'
//import { } from '@/composables'

const $route = useRoute();
const $router = useRouter();
useTitle($route.meta.title);

const canvasRef = ref(null);
const imgUrl = ref('');
const imgSrc = ref('');
const flag = ref(true);
const ref_width = ref('');
const ref_height = ref('');

const revision = $route.query.revision; // revision 植被编号
const raw_data = ref([]);
const tree_data = ref({});

const posterIndex = ref(0);

onMounted(async () => {
  const { code, data } = await getTreeAPI();
  if (code) {
    raw_data.value = data.filter(item => item.is_light === '1' || item.is_tree === 0); // 获取已点亮的植被/全点亮的图片
    let index = raw_data.value.findIndex(item => item.revision == revision); // 植被信息index
    tree_data.value = raw_data.value[index]; // 获取当前植被信息
    imgSrc.value = tree_data.value.user_poster !== null ? tree_data.value.user_poster : tree_data.value.poster_pic;
  }
  nextTick(() => {
    let canvasDom = canvasRef.value;
    ref_width.value = canvasDom.offsetWidth + 'px';
    ref_height.value = canvasDom.offsetHeight + 'px';
  });
  createImage();
});

const resizePoster = () => { // 重置海报
  tree_data.value = raw_data.value[posterIndex.value];
  flag.value = true;
  imgUrl.value = '';
  imgSrc.value = tree_data.value.user_poster !== null ? tree_data.value.user_poster : tree_data.value.poster_pic;
  nextTick(() => {
    let canvasDom = canvasRef.value;
    ref_width.value = canvasDom.offsetWidth + 'px';
    ref_height.value = canvasDom.offsetHeight + 'px';
  });
  createImage();
};

const goToIndex = () => { // 返回首页
  $router.push({
    path: '/',
  });
}

const posterPrev = () => { // 上一个
  if (posterIndex.value > 0) {
    posterIndex.value--;
  } else {
    posterIndex.value = raw_data.value.length - 1;
  }
  resizePoster();
};

const posterNext = () => { // 下一个
  if (posterIndex.value < raw_data.value.length - 1) {
    posterIndex.value++;
  } else {
    posterIndex.value = 0;
  }
  resizePoster();
};

// 获取像素比
const DPR = () => {
  // 获取设备dpi
  if (window.devicePixelRatio && window.devicePixelRatio > 1) {
    return window.devicePixelRatio * 2
  }
  // 直接返回高像素比
  return 8
}

const createImage = () => {
  nextTick(() => {
    // 获取要生成图片的 DOM 元素
    let canvasDom = canvasRef.value;
    const options = {
      backgroundColor: '#fff',
      // canvas: canvas,
      useCORS: true,//配置允许跨域
      scale: DPR(),
      // windowWidth: document.body.scrollWidth,
      // windowHeight: document.body.scrollHeight,
      // x: 0,
      // y: window.pageYOffset,
      // allowTaint: true,
      // background: "#d21f2c", // 一定要添加背景颜色,否则出来的图片,背景全部都是透明的
      // dpi: 300 // 处理模糊问题
    };
    // console.log("获取指定的宽高", width, height, canvas);
    html2canvas(canvasDom, options)
      .then(canvas => {
        try {
          // 生成图片地址
          imgUrl.value = canvas.toDataURL("image/png");
          flag.value = false;
        } catch (e) {
          alert("图片跨域,保存失败");
        }
      })
      .catch(error => {
        console.error("绘制失败");
        console.error(error);
      });
  });
}

const upload_loading = ref(false);

const beforeRead = (file) => {
  if (file.type.indexOf('image') < 0) {
    showToast('请上传图片格式');
    return false;
  }

  // if (file.size > 1000 * 1024) {
  //   showToast('图片大小超过1M');
  //   return false;
  // }

  return true;
};

const afterRead = async (res) => {
  upload_loading.value = true;
  let affix = uuidv4();
  // 此时可以自行将文件上传至服务器
  let dataURL = res.content;
  let base64url = dataURL.slice(dataURL.indexOf(',') + 1);  // 截取前缀的base64   data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAnoAAAJeCAYAA.......
  // 获取七牛token
  const { token, key, code } = await qiniuTokenAPI({ filename: `${affix}_${res.file.name}`, file: base64url });
  if (code) {
    const config = {
      headers: {
        'Content-Type': 'application/octet-stream',
        'Authorization': 'UpToken ' + token,    // UpToken后必须有一个 ' '(空格)
      }
    }
    // 上传七牛服务器
    const { filekey, hash, image_info } = await qiniuUploadAPI('http://upload.qiniup.com/putb64/-1/key/' + key, base64url, config)
    if (filekey) {
      // 保存图片
      const { code, data } = await saveFileAPI({ filekey, hash, format: '0', height: '0', width: '0' });
      if (code) {
        // 保存海报图片
        const { code: tree_code, data: tree_data } = await savePosterAPI({ tree_revision: revision, poster_pic: data.src })
        if (tree_code) {
          flag.value = true;
          imgUrl.value = '';
          imgSrc.value = data.src;
          upload_loading.value = false;
          createImage();
        }
      }
    }
  }
};
</script>

<style lang="less" scoped>
.poster-page {
  height: 100vh;
  background-image: url('https://cdn.ipadbiz.cn/xfPark/post/public/bg.1713241290.jpg');
  background-size: 100%;
  overflow: auto;
  .poster-contain-wrapper {
    // height: calc(83vh - 2rem);
    padding: 1rem;
    .poster-contain {
      position: relative;
      padding: 1rem;
      background-color: #fff;
      .poster-text-boxer {
        z-index: 10;
        position: absolute;
        top: 3rem;
        left: 2rem;
        color: #FFF;
        writing-mode: vertical-lr;
        text-orientation: upright;
        .poster-text {
          position: relative;
          .name {
            font-size: 2.2rem;
            font-weight: bolder;
            letter-spacing: 5px;
            // text-shadow:
            // -2px -2px 0 #1F6D4E,
            // 2px -2px 0 #1F6D4E,
            // -2px  2px 0 #1F6D4E,
            // 2px  2px 0 #1F6D4E;
            -webkit-text-stroke: 1px #1F6D4E;
          }
          .nickname {
            writing-mode: lr;
            font-size: 0.95rem;
            position: absolute;
            top: 0.5rem;
            // left: 3.5rem;
            letter-spacing: 5px;
            color: #1F6D4E;
            padding: 0.5rem;
            background-image: url('https://cdn.ipadbiz.cn/xfPark/post/public/wenzi-bg.1713239032.png');
            background-repeat: no-repeat;
            background-size: 100% 100%;
          }
        }
      }
      img {
        width: 100%;
        height: 70vh;
      }
      .poster-mission {
        color: #363636;
        margin-top: 1rem;
      }
    }
  }
  .poster-control-wrapper {
    .save-text {
      text-align: center;
      margin-bottom: 0.5rem;
      color: #797572;
      font-size: 0.9rem;
    }
    .poster-control {
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin-bottom: 1rem;
      .poster-prev {
        // background-color: rgba(0, 0, 0, 0.3);
        // color: #FFF;
        // padding: 0.5rem 0.8rem 0.5rem 1rem;
        // border-top-right-radius: 15px;
        // border-bottom-right-radius: 15px;
        // font-size: 0.9rem;
        background-image: url('https://cdn.ipadbiz.cn/xfPark/post/public/left-btn.1713242078.png');
        background-repeat: no-repeat;
        background-size: 100% 100%;
        width: 3rem;
        height: 3rem;
      }
      .poster-next {
        // background-color: rgba(0, 0, 0, 0.3);
        // color: #FFF;
        // padding: 0.5rem 1rem 0.5rem 0.8rem;
        // border-top-left-radius: 15px;
        // border-bottom-left-radius: 15px;
        // font-size: 0.9rem;
        background-image: url('https://cdn.ipadbiz.cn/xfPark/post/public/right-btn.1713242078.png');
        background-repeat: no-repeat;
        background-size: 100% 100%;
        width: 3rem;
        height: 3rem;
      }
      .poster-upload-btn {
        display: inline-block;
        // color: #fff;
        // padding: 0.5rem 2.5rem;
        // border-radius: 1.5rem;
        // font-size: 0.95rem;
        background-image: url('https://cdn.ipadbiz.cn/xfPark/post/public/poster-btn.1713242078.png');
        background-repeat: no-repeat;
        background-size: 100% 100%;
        width: 10rem;
        height: 3rem;
      }
    }
  }
}
</style>