You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

283 lines
8.4 KiB

8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
  1. <template>
  2. <view class="placard">
  3. <view class="placard-content">
  4. <view class="img-box" :style="{ width: canvasW + 'px', height: canvasH + 'px' }">
  5. <img v-show="tempFilePath" :style="{ width: canvasW + 'px', height: canvasH + 'px' }" :src="tempFilePath" alt="" />
  6. </view>
  7. <div class="qrcode" style="display: none;">
  8. <vue-qrcode :value="qrCodeValue" :width="qrCodeSize"
  9. :color="{ dark: qrCodeDarkColor, light: qrCodeLightColor }" :margin="margin"
  10. type="image/png"></vue-qrcode>
  11. </div>
  12. <canvas :style="{ width: canvasW + 'px', height: canvasH + 'px' }"
  13. canvas-id="myCanvas" id="myCanvas"></canvas>
  14. <view class="add-btn">
  15. <view class="btn">
  16. 长按图片保存到手机
  17. </view>
  18. </view>
  19. </view>
  20. </view>
  21. </template>
  22. <script>
  23. import drawTextVertical from '@/utils/Canvas.js'
  24. import VueQrcode from 'vue-qrcode'
  25. export default {
  26. name: 'Placard',
  27. components : { VueQrcode },
  28. data() {
  29. return {
  30. qrCodeValue: '',
  31. // qrCodeValue: import.meta.env.VITE_REDIRECT_URI + `?vid=${this.getUserInfo()}`,
  32. qrCodeSize: 180 * (window.innerWidth / 750),
  33. qrCodeDarkColor: '#000',
  34. qrCodeLightColor: '#fff',
  35. margin: 0,
  36. //画布信息
  37. canvasW: 299,
  38. canvasH: 403,
  39. //设备信息
  40. systemInfo: {},
  41. //图片路径
  42. tempFilePath: '',
  43. _rpx: 0,
  44. _center: 0
  45. }
  46. },
  47. created(){
  48. console.log(this.configList);
  49. console.log(this.configList.user_url);
  50. this.qrCodeValue = `${this.configList.user_url}?vid=${this.userInfo.id}`
  51. },
  52. methods: {
  53. async draw() { //绘制海报
  54. uni.showLoading({
  55. title: '拼命绘画中...'
  56. })
  57. let self = this
  58. //获取设备信息
  59. self.systemInfo = await self.getSystemInfo();
  60. //转换相对单位
  61. let rpx = self.systemInfo.windowWidth / 750
  62. self._rpx = rpx
  63. //设置画布宽高
  64. self.canvasW = 542 * rpx
  65. self.canvasH = 731 * rpx
  66. //海报背景
  67. let bg = new Image();
  68. bg.src = this.configList.qr_code_image
  69. // bg.src = this.configList.user_url + '/static/placard/placard-bg.png'
  70. //logo
  71. let logo = new Image();
  72. logo.src = this.configList.logo_image
  73. // logo.src = import.meta.env.VITE_REDIRECT_URI + '/static/placard/logo.png'
  74. console.log(this.configList.logo_image);
  75. bg.onload = () => {
  76. logo.onload = () => { //确保背景和logo加载完成(不然海报可能会少logo)
  77. setTimeout(() => {
  78. let ctx = document.querySelector('canvas').getContext('2d')
  79. let img = document.querySelector('.qrcode img')
  80. let center = self.canvasW / 2; //画布中心位置
  81. self._center = center
  82. //绘制图片
  83. ctx.drawImage(bg, 0, 0, self.canvasW, self.canvasH)
  84. ctx.drawImage(img, center - (self.qrCodeSize / 2), 295 * rpx, self.qrCodeSize, self
  85. .qrCodeSize)
  86. ctx.drawImage(logo, center - (100 * rpx / 2) , 60 * rpx , 100 * rpx, 100 * rpx)
  87. //绘制文字
  88. ctx.font = `bold ${40 * rpx}px 楷体`
  89. ctx.textAlign = 'center'
  90. ctx.fillStyle = "#59B495";
  91. ctx.fillText('上门服务', center, 200 * rpx, 400)
  92. ctx.fillStyle = "#0A543B";
  93. ctx.font = `100 ${25 * rpx}px 楷体`
  94. ctx.fillText(`一扫疲劳 舒服入眠`, center, 240 * rpx, 400)
  95. ctx.font = `100 ${25 * rpx}px 宋体`
  96. ctx.fillStyle = "#0A543B";
  97. ctx.textAlign = 'center';
  98. drawTextVertical(ctx, '微信扫码下单', 130 * rpx, 315 * rpx, self.qrCodeSize);
  99. ctx.textAlign = 'center';
  100. drawTextVertical(ctx, '在线选择技师', 400 * rpx, 315 * rpx, self.qrCodeSize);
  101. ctx.font = `100 ${18 * rpx}px 宋体`
  102. ctx.fillStyle = '#053323'
  103. ctx.fillText(`长按扫一扫下单可领取`, center, 525 * rpx, 400)
  104. ctx.font = `bold ${43 * rpx}px 宋体`
  105. ctx.fillStyle = '#EC8D44'
  106. ctx.fillText(`200元`, center, 580 * rpx, 400)
  107. ctx.font = `100 ${18 * rpx}px 宋体`
  108. ctx.fillText(`百万明星技师在线接单`, center, 625 * rpx, 400)
  109. //画图形
  110. this.paintingCapsule(ctx, center - (90 * rpx / 2), 250 * rpx, 90 * rpx, 25 * rpx,
  111. 13 * rpx, '#59B495', 'time')
  112. this.paintingCapsule(ctx, center + (130 * rpx / 2), 530 * rpx, 25 * rpx, 70 * rpx,
  113. 13 * rpx, '#BCEED6', 'coupon')
  114. ////画海报最后的标签列表
  115. this.drawList(ctx, 135 * rpx, 650 * rpx, 60 * rpx, 20 * rpx, 10 * rpx, '#59B495')
  116. uni.canvasToTempFilePath({
  117. x: 0, // 起点坐标
  118. y: 0,
  119. width: self.canvasW, // canvas 宽
  120. height: self.canvasH, // canvas 高
  121. canvasId: 'myCanvas', // canvas id
  122. success(res) {
  123. uni.hideLoading()
  124. self.tempFilePath = res.tempFilePath //相对路径
  125. }
  126. })
  127. })
  128. }
  129. }
  130. },
  131. // 获取设备信息
  132. getSystemInfo() {
  133. return new Promise((req, rej) => {
  134. uni.getSystemInfo({
  135. success: function(res) {
  136. req(res)
  137. }
  138. });
  139. })
  140. },
  141. paintingCapsule(ctx, x, y, width, height, radius, color, current) { //画椭圆(胶囊)
  142. // 开始新的路径
  143. ctx.beginPath();
  144. // 绘制左上角圆角
  145. ctx.moveTo(x + radius, y);
  146. ctx.arcTo(x + width, y, x + width, y + height, radius);
  147. // 绘制右上角圆角
  148. ctx.arcTo(x + width, y + height, x, y + height, radius);
  149. // 绘制右下角圆角
  150. ctx.arcTo(x, y + height, x, y, radius);
  151. // 绘制左下角圆角
  152. ctx.arcTo(x, y, x + width, y, radius);
  153. // 闭合路径(实际上在arcTo后已经是闭合的,但显式调用可以增加可读性)
  154. ctx.closePath();
  155. // 设置填充颜色
  156. ctx.fillStyle = color;
  157. // 填充路径
  158. ctx.fill();
  159. //下面是再写不同区域的内容
  160. if (current == 'time') {
  161. ctx.fillStyle = "#fff";
  162. ctx.font = `100 ${17 * this._rpx}px 楷体`
  163. ctx.fillText(`24小时`, this._center, 267 * this._rpx);
  164. } else if (current == 'coupon') {
  165. ctx.fillStyle = "#EC8D44";
  166. ctx.font = `100 ${13 * this._rpx}px 楷体`
  167. let offset = 13 * this._rpx
  168. drawTextVertical(ctx, '优惠券', 349 * this._rpx, 555 * this._rpx, height - offset);
  169. }
  170. },
  171. drawList(ctx, x, y, width, height, radius, color) { //画海报最后的标签列表
  172. let list = ['安全', '正规', '健康', '便捷']
  173. let offset = 15 //偏移量
  174. let currentTagInfo = {
  175. x
  176. }
  177. list.forEach(item => {
  178. // 开始新的路径
  179. ctx.beginPath();
  180. // 绘制左上角圆角
  181. ctx.moveTo(currentTagInfo.x + radius, y);
  182. ctx.arcTo(currentTagInfo.x + width, y, currentTagInfo.x + width, y + height, radius);
  183. // 绘制右上角圆角
  184. ctx.arcTo(currentTagInfo.x + width, y + height, currentTagInfo.x, y + height, radius);
  185. // 绘制右下角圆角
  186. ctx.arcTo(currentTagInfo.x, y + height, currentTagInfo.x, y, radius);
  187. // 绘制左下角圆角
  188. ctx.arcTo(currentTagInfo.x, y, currentTagInfo.x + width, y, radius);
  189. // 设置边框颜色
  190. ctx.strokeStyle = color;
  191. // 设置边框宽度(可选)
  192. ctx.lineWidth = 1; // 或者你想要的任何宽度
  193. // 闭合路径(实际上在arcTo后已经是闭合的,但显式调用可以增加可读性)
  194. ctx.closePath();
  195. // 绘制边框
  196. ctx.stroke();
  197. //圆点
  198. ctx.beginPath();
  199. ctx.fillStyle = color;
  200. ctx.arc(currentTagInfo.x + (10 * this._rpx), y + (10 * this._rpx), 2, 0,360)
  201. ctx.fill()
  202. //绘制文本
  203. ctx.font = `100 ${13 * this._rpx}px 楷体`
  204. ctx.fillText(item, currentTagInfo.x + (33 * this._rpx), y + (15 * this._rpx), 400)
  205. let next = currentTagInfo.x + width + offset; //下一个标签的位置
  206. currentTagInfo = { x : next }
  207. })
  208. },
  209. }
  210. }
  211. </script>
  212. <style lang="scss" scoped>
  213. .placard {
  214. display: flex;
  215. min-height: 100vh;
  216. align-items: center;
  217. justify-content: center;
  218. .placard-content{
  219. display: flex;
  220. flex-direction: column;
  221. align-items: center;
  222. .add-btn {
  223. display: flex;
  224. justify-content: center;
  225. align-items: center;
  226. height: 100rpx;
  227. width: 750rpx;
  228. .btn {
  229. display: flex;
  230. align-items: center;
  231. justify-content: center;
  232. width: 72%;
  233. height: 80rpx;
  234. border-radius: 40rpx;
  235. color: white;
  236. font-size: 28rpx;
  237. background: linear-gradient(180deg, #6FDFBE, #5AC796);
  238. margin-top: 40rpx;
  239. }
  240. }
  241. }
  242. }
  243. canvas{
  244. opacity: 1;
  245. position: fixed;
  246. top: 100%;
  247. left: 0;
  248. }
  249. </style>