share.vue 6.2 KB

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