index.vue 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. <template>
  2. <div class="code-container">
  3. <transition name="fade">
  4. <div v-if="isVisible" class="qrcode">
  5. <div class="title">{{ productInfo.productName }}</div>
  6. <div class="sncode"><span>仪器SN码:</span>{{ hanldeSNcode(productInfo.snCode) }}</div>
  7. <div class="content">
  8. <img :src="imgUrl" alt="">
  9. </div>
  10. <div class="btn down-btn" @click="handleDown">下载二维码</div>
  11. <div class="btn close-btn" @click="handleClose">关闭</div>
  12. </div>
  13. </transition>
  14. <canvas id="canvas" style="display:none" />
  15. <div v-if="isVisible" class="mask" @click="handleClose" />
  16. <a id="downloadLink" href="#" style="display:none" />
  17. </div>
  18. </template>
  19. <script>
  20. import QRCode from 'qrcode'
  21. import downImage from '@/assets/img/qrcode-bg-down.jpg'
  22. export default {
  23. name: 'Qrcode',
  24. filters: {
  25. },
  26. props: {
  27. productInfo: {
  28. type: Object,
  29. default: () => {}
  30. },
  31. isVisible: {
  32. type: Boolean,
  33. default: false
  34. }
  35. },
  36. data() {
  37. return {
  38. imgUrl: '',
  39. wwwServer: process.env.VUE_APP_BASE_API,
  40. qrcodePath: ''
  41. }
  42. },
  43. created() {
  44. this.qrcodePath = `${this.wwwServer}/product/auth/product-${this.productInfo?.productId}.html`
  45. this.initQrcode()
  46. },
  47. methods: {
  48. // 关闭二维码
  49. handleClose() {
  50. this.$emit('close')
  51. },
  52. // 下载二维码
  53. handleDown() {
  54. this.createDownFile((downCanvas) => {
  55. // 构造url
  56. var url = downCanvas.toDataURL('image/jpg')
  57. // 构造a标签并模拟点击
  58. var downloadLink = document.getElementById('downloadLink')
  59. downloadLink.setAttribute('href', url)
  60. downloadLink.setAttribute('download', '二维码.jpg')
  61. downloadLink.click()
  62. })
  63. },
  64. // 初始化二维码
  65. async initQrcode() {
  66. // 二维码配置
  67. const options = {
  68. width: 192,
  69. height: 192,
  70. margin: 1
  71. }
  72. try {
  73. this.imgUrl = await QRCode.toDataURL(this.qrcodePath, options)
  74. } catch (err) {
  75. console.error(err)
  76. }
  77. },
  78. // 生成下载的文件
  79. async createDownFile(callback) {
  80. const strHeader = this.productInfo.productName
  81. const strFooter1 = '仪器SN码:'
  82. const strFooter2 = this.hanldeSNcode(this.productInfo.snCode)
  83. // 生成二维码参数信息
  84. const options = {
  85. width: 720,
  86. height: 720,
  87. margin: 1
  88. }
  89. // 生成二维码dataURL
  90. const downDataURL = await QRCode.toDataURL(this.qrcodePath, options)
  91. // 设置下载二维码
  92. const downCanvas = document.getElementById('canvas')
  93. const downImg = new Image()
  94. const downBgImg = new Image()
  95. downImg.src = downDataURL
  96. downBgImg.src = downImage
  97. downBgImg.onload = function() {
  98. // 重新绘制画布
  99. const w = this.width
  100. const h = this.height
  101. downCanvas.width = w
  102. downCanvas.height = h
  103. const ctx = downCanvas.getContext('2d')
  104. // 设置画布背景
  105. ctx.fillStyle = '#ffffff'
  106. ctx.fillRect(0, 0, downCanvas.width, downCanvas.height)
  107. // 设置文字样式
  108. ctx.fillStyle = '#ffffff'
  109. ctx.font = 'bold 52px MicrosoftYaHei'
  110. ctx.textAlign = 'center'
  111. // 绘制背景
  112. ctx.drawImage(this, 0, 0)
  113. // 绘制二维码
  114. ctx.drawImage(downImg, 185, 372)
  115. // 绘制顶部文字描述
  116. const chr = strHeader.split('')
  117. let temp = ''
  118. const row = []
  119. for (let a = 0; a < chr.length; a++) {
  120. if (ctx.measureText(temp).width >= (w - 290)) {
  121. row.push(temp)
  122. temp = ''
  123. }
  124. temp += chr[a]
  125. }
  126. row.push(temp)
  127. if (row.length === 1) {
  128. ctx.fillText(row[0], w / 2, 122)
  129. } else {
  130. for (var b = 0; b < row.length; b++) {
  131. ctx.fillText(row[b], w / 2, 160 - (row.length - b - 1) * 65)
  132. }
  133. }
  134. // 绘制底部文字
  135. ctx.fillStyle = '#42aaff'
  136. ctx.font = 'bold 33px MicrosoftYaHei'
  137. ctx.textAlign = 'center'
  138. ctx.fillText(strFooter1 + strFooter2, w / 2, 238)
  139. // 绘制完成后的回调
  140. callback(downCanvas)
  141. }
  142. },
  143. hanldeSNcode(code) {
  144. const start = code.slice(0, 2)
  145. const end = code.slice(code.length - 5, code.length - 1)
  146. return start + '*'.repeat(6) + end
  147. }
  148. }
  149. }
  150. </script>
  151. <style lang="scss" scoped>
  152. .mask{
  153. position: fixed;
  154. top: 0;
  155. left: 0;
  156. z-index: 9998;
  157. width: 100vw;
  158. height: 100vh;
  159. background: rgba(0,0,0,.5);
  160. }
  161. .qrcode{
  162. z-index: 9999;
  163. position: fixed;
  164. left: 50%;
  165. top: 20%;
  166. transform: translateX(-50%);
  167. width: 300px;
  168. height: 400px;
  169. background: url(../../assets/img/qrcode-bg-show.png) no-repeat center;
  170. .content{
  171. width: 192px;
  172. height: 192px;
  173. position: absolute;
  174. left: 54px;
  175. bottom: 46px;
  176. }
  177. .down-btn{
  178. left: 0;
  179. }
  180. .close-btn{
  181. right: 0;
  182. }
  183. .title{
  184. position: absolute;
  185. top: 32px;
  186. left: 50%;
  187. transform: translateX(-50%);
  188. width:256px;
  189. text-align: center;
  190. font-size: 16px;
  191. color: #fff;
  192. font-weight: bold;
  193. }
  194. .sncode{
  195. position: absolute;
  196. top: 78px;
  197. left: 50%;
  198. transform: translateX(-50%);
  199. text-align: center;
  200. width: 192px;
  201. color: #0e9ef0;
  202. font-size: 14px;
  203. span{
  204. font-weight: bold;
  205. }
  206. }
  207. }
  208. .btn {
  209. position: absolute;
  210. bottom: -60px;
  211. width: 108px;
  212. height: 32px;
  213. background-image: linear-gradient(-90deg, #50c0ff 0%,#0e90dc 100%);
  214. border-radius: 4px;
  215. text-align: center;
  216. line-height: 32px;
  217. color: #fff;
  218. font-size: 14px;
  219. cursor: pointer;
  220. }
  221. </style>