share.vue 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. <template>
  2. <view class="container">
  3. <!-- 任务模板信息卡片 -->
  4. <view class="package-card">
  5. <image class="cover" :src="pkg.coverImage || '/static/default-cover.png'" mode="aspectFill" />
  6. <view class="package-info">
  7. <text class="name">{{ pkg.name }}</text>
  8. <text class="desc">{{ pkg.description }}</text>
  9. <view class="meta">
  10. <text>{{ pkg.cycleDays }}天</text>
  11. <text class="price">{{ formatPriceWithSymbol(pkg.price) }}</text>
  12. </view>
  13. </view>
  14. </view>
  15. <!-- 分享选项 -->
  16. <view class="share-options">
  17. <text class="section-title">分享给家长</text>
  18. <view class="option-item" @click="copyShareCode">
  19. <text class="option-icon">📋</text>
  20. <text class="option-text">复制分享码</text>
  21. </view>
  22. <view class="option-item" @click="generatePoster">
  23. <text class="option-icon">🖼️</text>
  24. <text class="option-text">生成分享海报</text>
  25. </view>
  26. <view class="option-item" @click="shareToFriend">
  27. <text class="option-icon">📱</text>
  28. <text class="option-text">发送给朋友</text>
  29. </view>
  30. </view>
  31. <!-- 海报预览 -->
  32. <uni-popup ref="posterPopup" type="center">
  33. <view class="poster-popup">
  34. <text class="poster-title">分享海报</text>
  35. <canvas canvas-id="posterCanvas" class="poster-canvas"></canvas>
  36. <view class="poster-actions">
  37. <button class="btn-save" @click="savePoster">保存图片</button>
  38. <button class="btn-share" open-type="share">转发给朋友</button>
  39. </view>
  40. <text class="close-btn" @click="closePoster">关闭</text>
  41. </view>
  42. </uni-popup>
  43. </view>
  44. </template>
  45. <script>
  46. import { getPackage } from '@/utils/api.js'
  47. export default {
  48. data() {
  49. return {
  50. pkgId: null,
  51. pkg: {},
  52. shareCode: ''
  53. }
  54. },
  55. onLoad(options) {
  56. this.pkgId = options.id
  57. this.loadPackage()
  58. },
  59. methods: {
  60. async loadPackage() {
  61. try {
  62. const res = await getPackage(this.pkgId)
  63. this.pkg = res.data || {}
  64. this.shareCode = this.pkg.shareCode || ''
  65. } catch (e) {
  66. console.error(e)
  67. }
  68. },
  69. copyShareCode() {
  70. uni.setClipboardData({ data: this.shareCode })
  71. uni.showToast({ title: '已复制分享码' })
  72. },
  73. generatePoster() {
  74. const ctx = uni.createCanvasContext('posterCanvas')
  75. // 背景
  76. ctx.setFillStyle('#ffffff')
  77. ctx.fillRect(0, 0, 600, 900)
  78. // 封面图(简化处理,实际需要下载图片)
  79. ctx.setFillStyle('#4CAF50')
  80. ctx.fillRect(0, 0, 600, 300)
  81. // 标题
  82. ctx.setFillStyle('#333333')
  83. ctx.setFontSize(32)
  84. ctx.fillText(this.pkg.name || '任务模板名称', 30, 350)
  85. // 描述
  86. ctx.setFillStyle('#666666')
  87. ctx.setFontSize(24)
  88. const desc = this.pkg.description || '暂无描述'
  89. ctx.fillText(desc.substring(0, 30), 30, 400)
  90. if (desc.length > 30) {
  91. ctx.fillText(desc.substring(30, 60), 30, 430)
  92. }
  93. // 周期和价格
  94. ctx.setFillStyle('#333333')
  95. ctx.setFontSize(28)
  96. ctx.fillText(`${this.pkg.cycleDays}天`, 30, 480)
  97. ctx.setFillStyle('#f44336')
  98. ctx.setFontSize(36)
  99. ctx.fillText(this.formatPriceWithSymbol(this.pkg.price), 30, 520)
  100. // 分享码
  101. ctx.setFillStyle('#4CAF50')
  102. ctx.setFontSize(24)
  103. ctx.fillText('分享码: ' + this.shareCode, 30, 580)
  104. // 提示文字
  105. ctx.setFillStyle('#999999')
  106. ctx.setFontSize(20)
  107. ctx.fillText('微信扫码或输入分享码查看任务模板', 30, 640)
  108. // 品牌标识
  109. ctx.setFillStyle('#cccccc')
  110. ctx.setFontSize(16)
  111. ctx.fillText('浠艾福', 480, 880)
  112. ctx.draw()
  113. this.$refs.posterPopup.open()
  114. },
  115. savePoster() {
  116. uni.canvasToTempFilePath({
  117. canvasId: 'posterCanvas',
  118. success: (res) => {
  119. uni.saveImageToPhotosAlbum({
  120. filePath: res.tempFilePath,
  121. success: () => {
  122. uni.showToast({ title: '已保存到相册' })
  123. },
  124. fail: () => {
  125. uni.showToast({ title: '保存失败', icon: 'none' })
  126. }
  127. })
  128. },
  129. fail: () => {
  130. uni.showToast({ title: '生成失败', icon: 'none' })
  131. }
  132. })
  133. },
  134. shareToFriend() {
  135. // 触发分享
  136. },
  137. closePoster() {
  138. this.$refs.posterPopup.close()
  139. }
  140. }
  141. }
  142. </script>
  143. <style scoped>
  144. .container { min-height: 100vh; background: #f5f5f5; padding: 30rpx; }
  145. .package-card { background: #fff; border-radius: 16rpx; overflow: hidden; margin-bottom: 30rpx; }
  146. .cover { width: 100%; height: 300rpx; }
  147. .package-info { padding: 30rpx; }
  148. .name { font-size: 34rpx; font-weight: bold; color: #333; display: block; margin-bottom: 10rpx; }
  149. .desc { font-size: 26rpx; color: #666; display: block; margin-bottom: 20rpx; }
  150. .meta { display: flex; align-items: center; gap: 20rpx; font-size: 26rpx; }
  151. .price { font-size: 34rpx; color: #f44336; font-weight: bold; }
  152. .share-options { background: #fff; border-radius: 16rpx; padding: 30rpx; }
  153. .section-title { font-size: 30rpx; font-weight: bold; display: block; margin-bottom: 20rpx; }
  154. .option-item { display: flex; align-items: center; padding: 30rpx 0; border-bottom: 1rpx solid #f0f0f0; }
  155. .option-item:last-child { border-bottom: none; }
  156. .option-icon { font-size: 40rpx; margin-right: 20rpx; }
  157. .option-text { font-size: 28rpx; color: #333; }
  158. .poster-popup { background: #fff; border-radius: 16rpx; padding: 30rpx; width: 600rpx; }
  159. .poster-title { font-size: 32rpx; font-weight: bold; display: block; text-align: center; margin-bottom: 20rpx; }
  160. .poster-canvas { width: 600rpx; height: 900rpx; background: #f5f5f5; margin: 0 auto; }
  161. .poster-actions { display: flex; gap: 20rpx; margin-top: 20rpx; }
  162. .btn-save, .btn-share { flex: 1; background: #4CAF50; color: #fff; font-size: 28rpx; }
  163. .btn-share { background: #2196F3; }
  164. .close-btn { display: block; text-align: center; margin-top: 20rpx; color: #999; font-size: 28rpx; }
  165. </style>