吉光研途前端代码仓库
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.

249 lines
6.0 KiB

  1. <template>
  2. <view class="page__view">
  3. <!-- 导航栏 -->
  4. <navbar leftClick @leftClick="$utils.navigateBack" bgColor="#4883F9" color="#FFFFFF" />
  5. <view style="width: 750rpx; height: 1184rpx; overflow: hidden;">
  6. <canvas id="myCanvas" canvas-id="firstCanvas1" type="2d" style="width: 100%; height: 100%;"></canvas>
  7. </view>
  8. <view class="flex bottom">
  9. <view class="flex">
  10. <button class="btn" @click="saveImg">保存到手机</button>
  11. </view>
  12. </view>
  13. </view>
  14. </template>
  15. <script>
  16. export default {
  17. data() {
  18. return {
  19. wxCodeImage: '',
  20. baseUrl: 'https://image.hhlm1688.com/',
  21. canvas: {},
  22. details: {},
  23. }
  24. },
  25. async onLoad({ thesisId }) {
  26. await this.getData(thesisId)
  27. await this.fetchQrCode()
  28. this.draw()
  29. },
  30. methods: {
  31. async getData(thesisId) {
  32. try {
  33. this.details = await this.$fetch('queryThesisById', { thesisId })
  34. } catch (err) {
  35. }
  36. },
  37. async fetchQrCode() {
  38. try {
  39. // todo: check api
  40. this.wxCodeImage = (await this.$fetch('getInviteCode'))?.url
  41. } catch (err) {
  42. }
  43. },
  44. drawTextWithManualLineBreaks(ctx, text, x, y, maxWidth, lineHeight) {
  45. let rows = 0
  46. let size = 0
  47. let lines = text.split('\n'); // 支持手动输入的换行符
  48. for (let lIdx = 0; lIdx < lines.length; lIdx++) {
  49. let line = lines[lIdx]
  50. let row = ''
  51. for (let wIdx = 0; wIdx < line.length; wIdx++) {
  52. let word = line[wIdx]
  53. let metrics = ctx.measureText(row + word);
  54. if (metrics.width > maxWidth) {
  55. rows++
  56. size += row.length
  57. console.log('--rows', rows, '--size', size)
  58. if (rows === 4 && size < text.length) {
  59. row = row.slice(0, -2) + '......'
  60. }
  61. ctx.fillText(row, x, y);
  62. row = ''
  63. y += lineHeight
  64. if (rows === 4) {
  65. break
  66. }
  67. } else {
  68. row += word
  69. }
  70. }
  71. if (rows === 4) {
  72. break
  73. }
  74. if (row) {
  75. rows++
  76. size += row.length
  77. console.log('--rows', rows, '--size', size)
  78. if (rows === 4 && size < text.length) {
  79. row = row.slice(0, -2) + '......'
  80. }
  81. ctx.fillText(row, x, y);
  82. y += lineHeight
  83. if (rows === 4) {
  84. break
  85. }
  86. }
  87. }
  88. },
  89. draw() {
  90. uni.showLoading({
  91. title: "拼命绘画中..."
  92. })
  93. wx.createSelectorQuery()
  94. .select('#myCanvas') // 绘制的canvas的id
  95. .fields({
  96. node: true,
  97. size: true
  98. })
  99. .exec(async (res) => {
  100. const canvas = res[0].node
  101. // 渲染上下文
  102. const ctx = canvas.getContext('2d')
  103. // Canvas 画布的实际绘制宽高
  104. const width = res[0].width
  105. const height = res[0].height
  106. // 初始化画布大小
  107. const dpr = wx.getWindowInfo().pixelRatio
  108. //根据dpr调整
  109. // dpr 2 4
  110. // 3 6
  111. console.log("--dpr", dpr)
  112. canvas.width = width * dpr
  113. canvas.height = height * dpr
  114. let Ratio = canvas.width / 750
  115. this.canvas = canvas
  116. ctx.scale(dpr, dpr)
  117. ctx.clearRect(0, 0, width, height)
  118. ctx.fillStyle = '#fff'
  119. ctx.fillRect(0, 0, canvas.width, canvas.height)
  120. ctx.fillStyle = '#999999';
  121. const fontSize = 28 * Ratio / dpr
  122. ctx.font = `${fontSize}px PingFangSC-regular`;
  123. const descX = 37 * Ratio / dpr
  124. const descY = 751 * Ratio / dpr
  125. const maxWidth = 677 * Ratio / dpr
  126. const lineHeight = 45 * Ratio / dpr
  127. this.drawTextWithManualLineBreaks(ctx, this.details.paperDesc, descX, descY, maxWidth, lineHeight)
  128. // 海报图片
  129. const paperImage = canvas.createImage()
  130. paperImage.src = this.details.paperImage
  131. paperImage.onload = () => {
  132. const x = 37 * Ratio / dpr
  133. const y = 21 * Ratio / dpr
  134. const w = 677 * Ratio / dpr
  135. const h = 687 * Ratio / dpr
  136. ctx.drawImage(paperImage, x, y, w, h)
  137. //二维码图片
  138. const coderImage = canvas.createImage()
  139. coderImage.src = this.wxCodeImage
  140. coderImage.onload = () => {
  141. const x = 539 * Ratio / dpr
  142. const y = 987 * Ratio / dpr
  143. const size = 162 * Ratio / dpr
  144. ctx.drawImage(coderImage, x, y, size, size)
  145. uni.hideLoading()
  146. }
  147. }
  148. })
  149. },
  150. saveImg() {
  151. this.$authorize('scope.writePhotosAlbum').then((res) => {
  152. this.imgApi()
  153. })
  154. },
  155. imgApi() {
  156. wx.canvasToTempFilePath({
  157. x: 0,
  158. y: 0,
  159. width: this.canvas.width,
  160. height: this.canvas.height,
  161. canvas: this.canvas,
  162. success: (res) => {
  163. let tempFilePath = res.tempFilePath;
  164. this.saveImgToPhone(tempFilePath)
  165. },
  166. fail: (err) => {
  167. console.log('--canvasToTempFilePath--fail', err)
  168. }
  169. }, this);
  170. },
  171. saveImgToPhone(image) {
  172. /* 获取图片的信息 */
  173. uni.getImageInfo({
  174. src: image,
  175. success: function(image) {
  176. /* 保存图片到手机相册 */
  177. uni.saveImageToPhotosAlbum({
  178. filePath: image.path,
  179. success: function() {
  180. uni.showModal({
  181. title: '保存成功',
  182. content: '图片已成功保存到相册',
  183. showCancel: false
  184. });
  185. },
  186. complete(res) {
  187. console.log(res);
  188. }
  189. });
  190. }
  191. });
  192. }
  193. },
  194. }
  195. </script>
  196. <style scoped lang="scss">
  197. .page__view {
  198. background: $uni-bg-color-grey;
  199. }
  200. .bottom {
  201. position: fixed;
  202. left: 0;
  203. bottom: 0;
  204. width: 100vw;
  205. height: 154rpx;
  206. padding-bottom: env(safe-area-inset-bottom);
  207. background: #FFFFFF;
  208. .btn {
  209. padding: 20rpx 77rpx;
  210. font-size: 28rpx;
  211. color: #FFFFFF;
  212. background: #4883F9;
  213. border-radius: 14rpx;
  214. }
  215. }
  216. </style>