| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500 |
- <template>
- <div
- class="print-wrap"
- v-show="true"
- >
- <div
- id="printMe"
- ref="printMe"
- v-if="elementStyle"
- :style="[elementStyle.canvas,defaultTemplate==='horizen'?{width:elementStyle.canvas.height,height:elementStyle.canvas.width}:{}]"
- >
- <div
- v-if="currentTicket"
- :style="[{ position: 'relative',width: elementStyle.canvas.width,height:elementStyle.canvas.height},defaultTemplate==='horizen'?{transform:elementStyle.canvas.reverse?'translateX(50%) rotate(90deg)':'translateX(-100%) rotate(-90deg)', transformOrigin:elementStyle.canvas.reverse?'0 0':'100% 0'}:{ transform:elementStyle.canvas.reverse?'rotate(180deg)':''}]">
- <div
- class="el sign"
- :style="elementStyle.sign">
- 窗
- </div>
- <span
- v-if="projectName!=='mazu'"
- class="el"
- :style="elementStyle.num">
- - NO.{{ isNaN(currentTicket.index)? 1 : currentTicket.index + 1 }} -
- </span>
- <span
- v-else
- class="el"
- :style="elementStyle.num">
- - NO.{{ isNaN(currentTicket.id)? '00000000' : currentTicket.id.toString().padStart(8,'0') }} -
- </span>
- <!-- 是否使用打印价格 -->
- <!--
- <span
- class="el"
- v-if="!currentTicket.is_otaorder"
- :style="elementStyle.price">
- <i style="font-size:0.8em; font-style:normal">{{ elementStyle.price&&elementStyle.price.format }}</i> ¥ {{ currentTicket.isPrint_price_active ? currentTicket.print_price*currentTicket.checkNum : currentTicket.price }} <span v-if="showUnit">元</span>
- </span>
- <span
- class="el"
- v-if="!currentTicket.is_otaorder"
- :style="elementStyle.singlePrice">
- <i style="font-size:0.8em; font-style:normal">{{ elementStyle.singlePrice&&elementStyle.singlePrice.format }}</i> ¥ {{ currentTicket.isPrint_price_active ? currentTicket.print_price : $NP.divide(currentTicket.price, currentTicket.checkNum) }} <span v-if="showUnit">元</span>
- </span>
- -->
- <!-- 三河古镇定制:线上订单也打印价格 -->
- <template v-if="'三河古镇' === scenicName">
- <span
- class="el"
- :style="elementStyle.price">
- <i style="font-size:0.8em; font-style:normal">{{ elementStyle.price&&elementStyle.price.format }}</i> ¥ {{ currentTicket.isPrint_price_active ? currentTicket.print_price*currentTicket.checkNum : currentTicket.price }} <span v-if="showUnit">元</span>
- </span>
- <span
- class="el"
- :style="elementStyle.singlePrice">
- <i style="font-size:0.8em; font-style:normal">{{ elementStyle.singlePrice&&elementStyle.singlePrice.format }}</i> ¥ {{ currentTicket.isPrint_price_active ? currentTicket.print_price : $NP.divide(currentTicket.price, currentTicket.checkNum) }} <span v-if="showUnit">元</span>
- </span>
- </template>
- <!-- 其余景区线上订单不打印价格 -->
- <template v-else>
- <span
- class="el"
- v-if="!currentTicket.is_otaorder"
- :style="elementStyle.price">
- <i style="font-size:0.8em; font-style:normal">{{ elementStyle.price&&elementStyle.price.format }}</i> ¥ {{ currentTicket.isPrint_price_active ? currentTicket.print_price*currentTicket.checkNum : currentTicket.price }} <span v-if="showUnit">元</span>
- </span>
- <span
- class="el"
- v-if="!currentTicket.is_otaorder"
- :style="elementStyle.singlePrice">
- <i style="font-size:0.8em; font-style:normal">{{ elementStyle.singlePrice&&elementStyle.singlePrice.format }}</i> ¥ {{ currentTicket.isPrint_price_active ? currentTicket.print_price : $NP.divide(currentTicket.price, currentTicket.checkNum) }} <span v-if="showUnit">元</span>
- </span>
- </template>
- <div :style="elementStyle.orderNo">
- {{ elementStyle.orderNo&&elementStyle.orderNo.format || '订单号:' }}{{ currentTicket.orderNo }}
- </div>
- <div
- :style="elementStyle.saleAdminName"
- v-if="currentTicket.saleAdminName">
- 售票员:{{ currentTicket.saleAdminName }}
- </div>
- <div
- :style="elementStyle.guestName"
- v-if="(currentTicket.buyerName||currentTicket.guestName)">
- {{ elementStyle.guestName.format&&elementStyle.guestName.format||'游客:' }} {{ currentTicket.guestName || currentTicket.buyerName }}
- <span v-if="currentTicket.guestIdentify && elementStyle.guestName.showId">({{ currentTicket.guestIdentify.replace(/^(.{6})(?:\d+)(.{4})$/,"$1******$2") }})</span>
- </div>
- <div
- :style="elementStyle.teamName"
- v-if="currentTicket.travelAgencyName">
- {{ elementStyle.teamName&&elementStyle.teamName.format||'旅行社:' }} {{ currentTicket.travelAgencyName }}
- </div>
- <div :style="elementStyle.ticketId">
- {{ elementStyle.ticketId&&elementStyle.ticketId.format || '票号:' }}{{ currentTicket.ticketNo }}
- </div>
- <div
- :style="elementStyle.createTime"
- v-if="currentTicket.createTime">
- {{ elementStyle.createTime&&elementStyle.createTime.format || '出票时间:' }}{{ currentTicket.buyTime }}
- </div>
- <div :style="elementStyle.scenics">
- {{ scenics }}
- </div>
- <div :style="elementStyle.scenic">
- <div :style="((elementStyle.scenic && (elementStyle.scenic.direction==='inline'|| !elementStyle.scenic.direction))?{}:{display: 'flex','flex-direction': 'column'})">
- <template v-if="elementStyle.scenic.number==='0'">
- <span
- style="margin-right:5px"
- v-for="(item,index) in scenicList"
- :key="index">
- {{ item.scenicName }} {{ item.checkLimitTimes }}次<span v-if="index!==(scenicList.length-1)">,</span>
- </span>
- </template>
- <template v-else>
- <span
- style="margin-right:5px"
- v-for="(item,index) in scenicList.slice(0,elementStyle.scenic.number||2)"
- :key="index">
- {{ item.scenicName }} {{ item.checkLimitTimes }}次<span v-if="elementStyle.scenic.number>scenicList.length?index!==(scenicList.length-1):index!==(elementStyle.scenic.number||2)-1">,</span>
- </span>
- <span v-if="elementStyle.scenic.number<scenicList.length">...(多景点门票)</span>
- </template>
- </div>
- </div>
- <!-- <table :style="elementStyle.info">
- <tr>
- <td width="40%">
- 订单号:
- </td>
- <td></td>
- </tr>
- <tr>
- <td>票号:</td>
- <td>{{ currentTicket.qrcode }}</td>
- </tr>
- <tr v-if="scenicList && scenicList.length>0">
- <td>{{ scenicList[0].scenicName }}</td>
- <td>
- 可检 {{ scenicList[0].checkLimitTimes }} 次
- 单次可过人数: {{ scenicList[0].single_pass_times }} 人 <br>
- <span v-if="scenicList.length>1">
- (多景点门票)
- </span>
- </td>
- </tr>
- </table> -->
- <div :style="elementStyle.ticketTypeName">
- {{ elementStyle.ticketTypeName&&elementStyle.ticketTypeName.format || '' }}{{ currentTicket.ticketTypeName }}
- </div>
- <div
- class="img"
- :style="[elementStyle.qrcode,{backgroundImage:`url(${qrImg})`}]">
- </div>
- <!--
- <div
- v-if="currentTicket.invoiceQrcode"
- class="img-wrap"
- :style="[elementStyle.invoiceQrcode,{display:currentTicket.invoiceQrcode?'block':'none'}]">
- <div
- class="img"
- :style="{backgroundImage:`url(${fpImg})`,height:'100%'}">
- </div>
- <div v-if="elementStyle.invoiceQrcode">
- {{ elementStyle.invoiceQrcode&&elementStyle.invoiceQrcode.format }}
- </div>
- </div>
- -->
- <!-- 不需要再设置display,否则它会覆盖elementStyle里设置的display -->
- <div
- v-if="currentTicket.invoiceQrcode"
- class="img-wrap"
- :style="[elementStyle.invoiceQrcode]">
- <div
- class="img"
- :style="{backgroundImage:`url(${fpImg})`,height:'100%'}">
- </div>
- <div v-if="elementStyle.invoiceQrcode">
- {{ elementStyle.invoiceQrcode&&elementStyle.invoiceQrcode.format }}
- </div>
- </div>
- <!--
- <div
- v-if="currentTicket.allInvoiceQrcode"
- class="img-wrap"
- :style="[elementStyle.allInvoiceQrcode,{display:currentTicket.allInvoiceQrcode?'block':'none'}]">
- <div
- class="img"
- :style="{backgroundImage:`url(${afpImg})`,height:'100%'}">
- </div>
- <div v-if="elementStyle.allInvoiceQrcode">
- {{ elementStyle.allInvoiceQrcode.format }}
- </div>
- </div>
- -->
- <!-- 不需要再设置display,否则它会覆盖elementStyle里设置的display -->
- <div
- v-if="currentTicket.allInvoiceQrcode"
- class="img-wrap"
- :style="[elementStyle.allInvoiceQrcode]">
- <div
- class="img"
- :style="{backgroundImage:`url(${afpImg})`,height:'100%'}">
- </div>
- <div v-if="elementStyle.allInvoiceQrcode">
- {{ elementStyle.allInvoiceQrcode.format }}
- </div>
- </div>
- <div :style="elementStyle.des">
- <span v-if="currentTicket.isNeedPlaytime">
- {{ elementStyle.des&&elementStyle.des.format||'游玩日期:' }}{{ currentTicket.payDateBegin | formatDate }} <br>
- </span>
- <span v-else>
- 有效日期: {{ currentTicket.payDateBegin | formatDate }} 至 {{ currentTicket.playDateEnd | formatDate }}<br>
- </span>
- </div>
- <div
- :style="elementStyle.orderRemark"
- v-if="currentTicket.remark">
- {{ elementStyle.orderRemark&&elementStyle.orderRemark.format||'订单备注:' }}{{ currentTicket.remark }}
- </div>
- <div
- :style="elementStyle.performName"
- v-if="currentTicket.performName">
- <!-- {{ elementStyle.performName&&elementStyle.performName.format||'节目:' }}{{ currentTicket.performName }} -->
- <!-- 草房子这个景点不显示后面的"草房子剧场" -->
- {{ elementStyle.performName&&elementStyle.performName.format||'节目:' }}{{ '草房子' === scenicName ? '' : currentTicket.performName }}
- </div>
- <div
- :style="elementStyle.batchConfigName"
- v-if="currentTicket.batchConfigName">
- {{ elementStyle.batchConfigName&&elementStyle.batchConfigName.format||'场次:' }}{{ currentTicket.batchConfigName }}
- </div>
- <div
- :style="elementStyle.serialNumber"
- v-if="currentTicket.serialNumber">
- {{ elementStyle.serialNumber&&elementStyle.serialNumber.format||'场次内序号:' }}{{ currentTicket.serialNumber }}
- </div>
- <div
- :style="elementStyle.queueSerialNumber"
- v-if="currentTicket.queue_info">
- <span>{{ elementStyle.queueSerialNumber&&elementStyle.queueSerialNumber.format||'排队序列号::' }}</span>
- <span> {{ currentTicket.queue_info.queue_serialNumber }}</span>
- </div>
- <div
- :style="elementStyle.schedule"
- v-if="currentTicket.scheduleConfigName">
- {{ elementStyle.schedule&&elementStyle.schedule.format||'班次:' }}{{ currentTicket.scheduleConfigName }}
- </div>
- <div
- :style="elementStyle.scheduleSerialNumber"
- v-if="currentTicket.scheduleSerialNumber">
- {{ elementStyle.scheduleSerialNumber&&elementStyle.scheduleSerialNumber.format||'班次内序号:' }}{{ currentTicket.scheduleSerialNumber }}
- </div>
- <div
- :style="elementStyle.areaName"
- v-if="currentTicket.seatAreaName">
- {{ elementStyle.areaName&&elementStyle.areaName.format||'区域:' }}{{ currentTicket.seatAreaName }}
- </div>
- <div
- :style="elementStyle.pricePlan"
- v-if="currentTicket.ticket_price_plan_name">
- {{ elementStyle.pricePlan&&elementStyle.pricePlan.format||'价格方案:' }}{{ currentTicket.ticket_price_plan_name }}
- </div>
- <div
- :style="elementStyle.seatNameNew"
- v-if="currentTicket.seatNameNew">
- {{ elementStyle.seatNameNew&&elementStyle.seatNameNew.format||'A区' }}{{ currentTicket.seatNameNew }}
- </div>
- <div
- :style="elementStyle.rowTag"
- v-if="currentTicket.seatRowTag">
- {{ currentTicket.seatRowTag }}{{ elementStyle.rowTag&&elementStyle.rowTag.format||'排' }}
- </div>
- <div
- :style="elementStyle.seatName"
- v-if="currentTicket.seatName">
- {{ currentTicket.seatName }}{{ elementStyle.seatName&&elementStyle.seatName.format||'座' }}
- </div>
- <div
- :style="elementStyle.batchConfigName"
- v-if="currentTicket.batchConfigName">
- {{ elementStyle.batchConfigName&&elementStyle.batchConfigName.format||'场次:' }}{{ currentTicket.batchConfigName }}
- </div>
- <div
- :style="elementStyle.schedule"
- v-if="currentTicket.scheduleConfigName">
- {{ elementStyle.schedule&&elementStyle.schedule.format||'班次:' }}{{ currentTicket.scheduleConfigName }}
- </div>
- <div
- :style="elementStyle.areaName"
- v-if="currentTicket.seatAreaName">
- {{ elementStyle.areaName&&elementStyle.areaName.format||'区域:' }}{{ currentTicket.seatAreaName }}
- </div>
- <div :style="elementStyle.checkNum">
- {{ elementStyle.checkNum&&elementStyle.checkNum.format||'检票人数:' }}{{ currentTicket.checkNum }} 人
- </div>
- <div :style="elementStyle.remark">
- {{ elementStyle.remark&&elementStyle.remark.format||'' }}<span
- style="white-space: pre-wrap;"
- v-html="elementStyle.canvas.remark.replace(/\n/g,'<br>')">
- </span>
- </div>
- <div :style="elementStyle.fixedText">
- {{ elementStyle.fixedText&&elementStyle.fixedText.format||'备注2:' }}
- </div>
- </div>
- </div>
- </div>
- </template>
- <script>
- import QRCode from 'qrcode'
- export default {
- computed: {
- elementStyle () {
- let style = {}
- if (this.customStyle) {
- console.log(this.customStyle)
- this.customStyle.elements.forEach(i => {
- style[i.type] = i.style
- })
- style.canvas = this.customStyle.canvas
- if (!style.scenic) {
- style.scenic = { display: 'none' }
- }
- }
- return this.customStyle ? style : null
- },
- scenicList () {
- return this.currentTicket?.ticketScenic || this.currentTicket?.ticketCheckScenicList || []
- },
- scenics () {
- if (this.currentTicket) {
- const scenics = this.scenicList.map(i => i.scenicName)
- return scenics.join(' - ')
- } else {
- return ''
- }
- },
- printTemplate () {
- return this.$store.state.app.printTemplate
- },
- showUnit () {
- return this.scenicName !== '狼山景区' && this.scenicName !== '军山景区'
- },
- scenicName () {
- return this.$localStore.get('scenicName') || this.$store.state.user.scenicName
- }
- },
- data () {
- return {
- projectName: process.env.VUE_APP_PROJECT,
- qrImg: '',
- fpImg: '',
- afpImg: '',
- customStyle: null,
- defaultTemplate: ''
- }
- },
- props: {
- preview: { // 仅预览时,不打印
- type: Boolean,
- default: false
- },
- currentTicket: {
- type: Object,
- default: () => ({})
- }
- },
- methods: {
- startPrint () {
- console.log('currentTicket', this.currentTicket)
- const webview = document.querySelector('#printWebview')
- let printDoc = this.$refs.printMe.outerHTML
- // if (this.preview) {
- console.log(printDoc)
- // return
- // }
- // webview.openDevTools()
- webview.send('webview-print-render', printDoc)
- },
- sendPrinter (style) {
- if (style) {
- this.customStyle = JSON.parse(JSON.stringify(style))
- this.defaultTemplate = this.customStyle.theme
- this.$nextTick(() => {
- this.startPrint()
- })
- } else {
- this.startPrint()
- }
- }
- },
- watch: {
- printTemplate: {
- handler (val) {
- if (val) {
- this.defaultTemplate = val.canvas && val.canvas.direction
- // console.log(this.defaultTemplate)
- this.customStyle = val
- }
- },
- deep: true,
- immediate: true
- },
- currentTicket: {
- handler (val) {
- if (!val) return
- let target
- if (val.print_model_id !== 0) {
- target = this.$store.state.app.printTemplateList.find(i => i.id === val.print_model_id)
- } else {
- let id = this.$localStore.get('defaultTemplate')
- target = this.$store.state.app.printTemplateList.find(i => i.id === id)
- }
- this.$store.commit('SET_PRINT_TEMPLATE', target ? JSON.parse(target.content) : this.printTemplate)
- this.$nextTick(async () => {
- var opts = {
- errorCorrectionLevel: 'H',
- type: 'image/png',
- quality: 1,
- color: {
- dark: '#000000ff', // Blue dots
- light: '#0000' // Transparent background
- }
- }
- if (this.currentTicket.ticketNo) {
- this.qrImg = await QRCode.toDataURL(this.currentTicket.ticketNo, opts)
- }
- if (this.currentTicket.invoiceQrcode) {
- this.fpImg = await QRCode.toDataURL(this.currentTicket.invoiceQrcode, opts)
- }
- if (this.currentTicket.allInvoiceQrcode) {
- this.afpImg = await QRCode.toDataURL(this.currentTicket.allInvoiceQrcode, opts)
- }
- console.warn(this.currentTicket)
- if (this.preview) return
- setTimeout(() => {
- this.sendPrinter()
- }, 100)
- })
- },
- immediate: true
- }
- }
- }
- </script>
- <style scoped>
- .img{
- height: 100%; background: no-repeat center center /contain;
- }
- </style>
|