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

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