123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385 |
- <template>
- <div class="flex flex-col items-stretch w-[24cm] max-w-[24cm]">
- <div class="flex justify-between">
- <div class="mb-2">
- <el-tooltip
- content="其实二维码在提交SO后就会自动刷新, 除非你点了右边的Clean QR Code"
- >
- <el-button
- class="custom-button"
- @click="reGenerateQrCode"
- >
- Generate QR Code
- </el-button>
- </el-tooltip>
- <el-tooltip content="除非你不想打印二维码">
- <el-button @click="qrcodeVisible = false">Clean QR Code</el-button>
- </el-tooltip>
- </div>
- <div>
- <el-button
- type="danger"
- @click="clean"
- >
- Clean Input Job
- </el-button>
- <el-tooltip content="确认下面的预览内容没问题再点打印">
- <el-button
- class="custom-button"
- :loading="printing"
- @click="onBtnPrint"
- >
- Print Page
- </el-button>
- </el-tooltip>
- </div>
- </div>
- <div class="">
- <el-form inline>
- <el-form-item
- v-if="scene === 'SO'"
- label="QR Code Content"
- class="text-left w-[100%]"
- >
- <div
- class="el-input el-input__wrapper el-input__inner cursor-not-allowed hover:cursor-not-allowed"
- >
- {{ selectedContent.map((i) => i.Reference).join(';') }}
- </div>
- </el-form-item>
- <el-form-item
- label="Total Page"
- style="width: 20%"
- prop="total"
- >
- <el-input
- v-model.number="total"
- :type="'number'"
- ></el-input>
- </el-form-item>
- <el-form-item
- label="Text direction"
- style="width: 15%"
- prop="rotated"
- >
- <el-switch v-model="rotated"></el-switch>
- </el-form-item>
- <el-form-item
- label="Page width(CM)"
- style="width: 20%"
- prop="pageWidth"
- >
- <el-input
- v-model.number="pageWidth"
- :type="'number'"
- ></el-input>
- </el-form-item>
- <el-form-item
- label="Page Height(CM)"
- style="width: 20%"
- prop="pageHeight"
- >
- <el-input
- v-model.number="pageHeight"
- :type="'number'"
- ></el-input>
- </el-form-item>
- <el-form-item
- label="Font Size"
- style="width: 50%"
- >
- <el-slider
- v-model="pdfFontSize"
- :step="1"
- ></el-slider>
- </el-form-item>
- <el-form-item
- style="width: 100%"
- label="箱唛"
- >
- <el-input
- v-model="mai"
- type="textarea"
- ></el-input>
- </el-form-item>
- <div class="flex gap-1">
- <div
- v-for="(item, index) in logoList"
- :key="item"
- class="w-[60px] h-[60px] bg-contain bg-center bg-no-repeat cursor-pointer"
- :style="{ backgroundImage: `url(${item})` }"
- @click="selectlogo(index)"
- ></div>
- </div>
- </el-form>
- </div>
- <br />
- <div class="flex flex-wrap">
- <div
- v-for="i in total"
- :key="i"
- :style="{
- width: `${pageWidth}cm`,
- height: `${pageHeight}cm`,
- }"
- class="pdf-wrap relative border border-solid border-gray-200 mb-2 mr-2"
- >
- <div
- :id="`pdfItem-${i}`"
- :ref="(el) => setElement(el, i)"
- class="pdf-area w-[100%] h-[100%] relative text-center p-4 flex flex-col items-stretch justify-center"
- :class="{}"
- :style="{
- width: rotated ? `${pageHeight}cm` : `${pageWidth}cm`,
- height: rotated ? `${pageWidth}cm` : `${pageHeight}cm`,
- transformOrigin: 'top left',
- transform: rotated ? 'rotate(90deg)' : '',
- right: rotated ? `-${pageWidth}cm` : '',
- }"
- >
- <!-- bottom: rotated ? `-${(i - 1) * (pageWidth - pageHeight)}cm` : '', -->
- <div
- class="mai font-medium break-all mb-4"
- :style="{
- fontSize: `${pdfFontSize}pt`,
- }"
- @dblclick="ElMessage.info('hello')"
- >
- {{ mai }}
- </div>
- <div class="flex justify-center">
- <div class="font-medium text-5xl">{{ i }} / {{ total }}</div>
- </div>
- <div class="flex gap-1 absolute bottom-4 left-4">
- <div
- v-for="item in selectedLogo"
- :key="item"
- class="w-[90px] h-[90px] bg-contain bg-center bg-no-repeat"
- :style="{ backgroundImage: `url(${item})` }"
- ></div>
- </div>
- <div
- v-show="qrcodeVisible"
- class="qrcode absolute bottom-4 right-4 w-[110px] h-[110px] border border-solid border-gray-400"
- >
- <img
- v-show="qrcodeURL.length"
- style="width: 100%; height: auto"
- :src="qrcodeURL"
- alt="qr-code"
- />
- </div>
- </div>
- </div>
- </div>
- </div>
- </template>
- <!-- todo 后续so search如果有更新, 引用这个组件. -->
- <script setup lang="ts">
- import {
- defineComponent,
- defineProps,
- nextTick,
- ref,
- watch,
- computed,
- } from 'vue'
- import {
- ElMessage,
- ElInput,
- ElButton,
- ElForm,
- ElFormItem,
- ElSlider,
- ElTooltip,
- ElSwitch,
- } from 'element-plus'
- import jspdf from 'jspdf'
- import qrcode from 'qrcode'
- import html2canvas from 'html2canvas'
- import debounce from 'lodash.debounce'
- defineComponent({
- name: 'ComponentPrint',
- })
- const { content = [], scene = 'SO', autoOpenQRCode = true } = defineProps<{
- content: any[]
- scene?: string
- autoOpenQRCode?: boolean
- }>()
- let selectedContent = ref([] as any[])
- const mai = ref('')
- watch(
- () => content,
- () => {
- selectedContent.value = content.slice()
- if (scene === 'SO') {
- mai.value = selectedContent.value
- .map((c: any) => `${c.Reference}_${c.Contract_Title}`)
- .join('; ')
- } else if (scene === 'QC') {
- mai.value = selectedContent.value.join('')
- }
- if (mai.value.length && autoOpenQRCode) {
- nextTick(() => {
- reGenerateQrCode()
- })
- }
- },
- { deep: true, immediate: true },
- )
- const clean = () => {
- mai.value = ''
- selectedContent.value = []
- }
- let qrcodeVisible = ref(false)
- let qrcodeURL = ref('')
- async function reGenerateQrCode() {
- await qrcode.toDataURL(
- mai.value,
- { errorCorrectionLevel: 'H' },
- function (err: any, url: any) {
- qrcodeURL.value = url
- },
- )
- qrcodeVisible.value = true
- }
- const pdfList = ref({} as any)
- const setElement = (el: any, index: number) => {
- pdfList.value[`${index}`] = el
- }
- const getLogoPath = (path: string) => {
- return new URL(path, import.meta.url).href
- }
- const logoList = ref([] as any[])
- async function getLogoList() {
- (
- [
- getLogoPath('/assets/label/heavy.png'),
- getLogoPath('/assets/label/keep_dry.png'),
- getLogoPath('/assets/label/place_up.png'),
- getLogoPath('/assets/label/care.png'),
- getLogoPath('/assets/label/glass.png'),
- ] as string[]
- ).forEach((i: string, index: number) => {
- fetch(i)
- .then((res) => res.blob())
- .then((blob) => (logoList.value[index] = URL.createObjectURL(blob)))
- })
- }
- getLogoList()
- const selectlogo = (index: number) => {
- const i = selectedLogoIndex.value.indexOf(index)
- if (i > -1) {
- selectedLogoIndex.value.splice(i, 1)
- } else {
- selectedLogoIndex.value.push(index)
- }
- }
- let selectedLogoIndex = ref([] as number[])
- let selectedLogo = computed(() =>
- logoList.value.filter((i: any, index: number) =>
- selectedLogoIndex.value.includes(index),
- ),
- )
- let total = ref(1 as number)
- let pdfFontSize = ref(32)
- let pageWidth = ref(20) // 目标pdf的页宽
- let pageHeight = ref(10) // 目标pdf的页高
- /**
- * 宽大于等于高
- */
- let orientation = computed(() => pageWidth.value >= pageHeight.value)
- let rotated = ref(false)
- let pdf: any = null
- let printing = ref(false)
- const reGeneratePDF = debounce(function () {
- printing.value = true
- pdf = null
- pdf = new jspdf({
- orientation: orientation.value ? 'l' : 'p',
- unit: 'cm',
- format: [pageWidth.value, pageHeight.value],
- })
- const pool = []
- for (const key in pdfList.value) {
- if (Object.prototype.hasOwnProperty.call(pdfList.value, key)) {
- pool.push(generatePDF(pdfList.value[key], key))
- }
- }
- Promise.all(pool).then(() => {
- printing.value = false
- })
- }, 300)
- watch(
- [
- total,
- mai,
- pdfFontSize,
- pageWidth,
- pageHeight,
- qrcodeVisible,
- rotated,
- selectedLogo,
- ],
- () => {
- nextTick(() => reGeneratePDF())
- },
- )
- async function onBtnPrint() {
- let fileName = ''
- switch (scene) {
- case 'QC':
- fileName = ''
- break
- default:
- fileName = selectedContent.value.map((i: any) => i.Reference).join('_')
- }
- window.open(
- // @ts-ignore 照着jspdf文档搬的...ts报错
- pdf.output('bloburl', {
- fileName,
- }),
- )
- }
- function generatePDF(pdfItem: HTMLElement, key: string) {
- return html2canvas(pdfItem, {
- allowTaint: true,
- useCORS: true,
- backgroundColor: '#fff', // 一定要设背景颜色,否则有的浏览器就会变花,比如Edge
- scale: 3, // 缩放倍率调整清晰度
- }).then((canvas) => {
- const width = canvas.width
- const height = canvas.height
- const image = new Image()
- const target = document.createElement('canvas')
- target.height = height
- target.width = width
- image.onload = function () {
- const ctx = target.getContext('2d')
- ctx?.drawImage(image, 0, 0)
- if (Number(key) > 1) pdf.addPage()
- pdf.addImage(
- target.toDataURL('image/jpeg', 1.0),
- 'JPEG',
- 0,
- 0,
- pageWidth.value,
- pageHeight.value,
- )
- }
- image.src = canvas.toDataURL('image/jpeg', 1.0)
- })
- }
- </script>
- <style scoped></style>
|