index.vue 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. <route lang="json">
  2. {
  3. "style": {
  4. "navigationBarTitleText": "邀请设计师",
  5. "navigationBarBackgroundColor": "#fff",
  6. "navigationStyle": "custom"
  7. }
  8. }
  9. </route>
  10. <script setup lang="ts">
  11. import SectionHeading from '@/components/section-heading.vue'
  12. import { getDesignerInfo, updateDesignerInfo } from '../../../core/libs/requests'
  13. import { useUserStore } from '../../../store'
  14. import { storeToRefs } from 'pinia'
  15. import { pick } from 'radash'
  16. import BottomAppBar from '@/components/bottom-app-bar.vue'
  17. import { useMessage } from 'wot-design-uni'
  18. import { NetImages } from '../../../core/libs/net-images'
  19. import NavbarEvo from '@/components/navbar-evo.vue'
  20. import ImageEvo from '@/components/image-evo.vue'
  21. import { Canvas } from '../../../core/utils/canvas'
  22. const { alert } = useMessage()
  23. const userStore = useUserStore()
  24. const { userInfo } = storeToRefs(userStore)
  25. const form = ref<{
  26. userId?: number
  27. videoNumber?: string
  28. }>()
  29. const windowInfo = ref<{}>
  30. const { data, run: setData } = useRequest(() => getDesignerInfo(userInfo.value.userId))
  31. const { loading, run: submiting } = useRequest(() => updateDesignerInfo(form.value))
  32. const posterUrl = ref()
  33. const canvasHidden = ref(false)
  34. const createPoster = () => {
  35. return new Promise((resolve, reject) => {
  36. ;(async () => {
  37. uni.showLoading({ title: '生成中' })
  38. const [path, bgPath, qrcode, logoPath, avatarPath, icon1, icon2, icon3, icon4] = await Promise.all(
  39. [
  40. data.value.sharePageUrl,
  41. NetImages.InviteBg,
  42. data.value.qrcodeUrl,
  43. NetImages.Logo,
  44. data.value.headImgUrl || userInfo.value?.avatar || NetImages.DefaultAvatar,
  45. 'https://image.zhuchaohui.com/zhucaohui/315c5ca680bc6b47a5344dbff701cf1e6802d8a240754e25ef3d4308bc1deef6.png',
  46. 'https://image.zhuchaohui.com/zhucaohui/ee83d30d553feb1482920e49c28824d73bb33838d996ec2f6c646ae6deab0330.png',
  47. 'https://image.zhuchaohui.com/zhucaohui/9f89604f285c33200b7e6fda9acc82e130f34c2f5687cfeb78f3541e1fabcc28.png',
  48. 'https://image.zhuchaohui.com/zhucaohui/2467be55426018856150bd94bbd21865df3d73ce982bc1c82b7585cf26c822f0.png',
  49. ].map((it) => uni.getImageInfo({ src: it }).then(({ path }) => path)),
  50. )
  51. const ctx = uni.createCanvasContext('firstCanvas')
  52. const getPx = (width, designPx) => {
  53. return (width / 319) * designPx
  54. }
  55. uni
  56. .createSelectorQuery()
  57. .select('#firstCanvas')
  58. .fields({ size: true }, async ({ width: w, height: h }: any) => {
  59. const canvas = new Canvas(ctx, { width: w, height: h }, { width: 319 })
  60. canvas.FillImage(bgPath)
  61. ctx.drawImage(path, 0, 0, w, w / 1.56)
  62. canvas.CircleImage(avatarPath, 17, 21, 14)
  63. canvas.Image(logoPath, 17, 230, 24, 24)
  64. canvas.Image(qrcode, 200, 350, 100, 100)
  65. canvas.FillText(userInfo.value?.nickname, '#ffffff', 14, 53, 40)
  66. canvas.FillText('筑巢荟—助力设计师成长平台', '#ffffff', 18, 53, 248)
  67. canvas.FillText('国内外设计游学', '#ffffff', 12, 62, 303)
  68. canvas.FillText('设计赋能项目', '#ffffff', 12, 207, 303)
  69. canvas.FillText('线上获客工具', '#ffffff', 12, 62, 339)
  70. canvas.FillText('丰富线下活动', '#ffffff', 12, 207, 339)
  71. canvas.Image(icon1, 41, 290, 18, 18)
  72. canvas.Image(icon2, 189, 290, 18, 18)
  73. canvas.Image(icon3, 41, 325, 18, 18)
  74. canvas.Image(icon4, 189, 325, 18, 18)
  75. ctx.draw(true, () => {
  76. uni.canvasToTempFilePath({
  77. canvasId: 'firstCanvas',
  78. width: 300,
  79. height: 460,
  80. fileType: "jpg",
  81. quality: 1,
  82. success: (res) => {
  83. // console.log('生成海报', res)
  84. uni.hideLoading()
  85. resolve(res.tempFilePath)
  86. },
  87. fail: (err) => {
  88. // uni.hideLoading()
  89. reject(err)
  90. },
  91. })
  92. })
  93. })
  94. .exec()
  95. })()
  96. })
  97. }
  98. const save = async () => {
  99. await uni.saveImageToPhotosAlbum({ filePath: posterUrl.value })
  100. uni.showToast({ title: '已保存相册', icon: 'none' })
  101. }
  102. const share = () => {
  103. // uni.share({
  104. // provider: 'weixin',
  105. // scene: 'WXSceneSession',
  106. // type: 2,
  107. // // title: '你好呀',
  108. // // href: 'https://www.baidu.com/',
  109. // // summary: '我是图文描述',
  110. // imageUrl: posterUrl.value,
  111. // success: function (res) {
  112. // console.log('success:' + JSON.stringify(res))
  113. // },
  114. // fail: function (err) {
  115. // console.log('fail:' + JSON.stringify(err))
  116. // },
  117. // })
  118. }
  119. onMounted(async () => {
  120. await setData()
  121. form.value = pick(data.value, ['id', 'userId', 'videoNumber'])
  122. uni.getWindowInfo()
  123. posterUrl.value = await createPoster()
  124. })
  125. // onAppShare(() => {})
  126. </script>
  127. <template>
  128. <div
  129. class="flex-grow flex flex-col justify-center gap-5 px-3.5 py-6 bg-black bg-[length:100%_100%]"
  130. :style="{ backgroundImage: `url(${NetImages.InviteBg})` }"
  131. >
  132. <NavbarEvo fixed transparent dark></NavbarEvo>
  133. <div class="block aspect-[0.69/1]">
  134. <div class="mx-7 aspect-[0.69/1] relative rounded-2xl overflow-hidden">
  135. <canvas
  136. class="w-full h-full absolute top--1000"
  137. canvas-id="firstCanvas"
  138. id="firstCanvas"
  139. ></canvas>
  140. <!-- <wd-img width="100%" height="100%" :src="posterUrl"></wd-img> -->
  141. <ImageEvo
  142. class="w-full h-full"
  143. :src="posterUrl"
  144. @displayed="canvasHidden = true"
  145. ></ImageEvo>
  146. <div class="absolute bottom-5.5 left-5.5 flex justify-between" v-if="canvasHidden">
  147. <!-- <cover-view> -->
  148. <wd-button custom-class="bg-white/10!" @click="save">保存到相册</wd-button>
  149. <!-- <div style="margin-left: 100rpx;">
  150. <wd-img :width="50" :height="50" :src="data.qrcodeUrl"></wd-img>
  151. </div> -->
  152. <!-- </cover-view> -->
  153. <!-- <wd-button @click="share">微信</wd-button>
  154. <wd-button @click="share">朋友圈</wd-button> -->
  155. </div>
  156. </div>
  157. </div>
  158. <!-- <SectionHeading title="如何关联视频号?" size="sm"></SectionHeading>
  159. <img class="w-[347px] h-[186px] rounded-2xl" src="https://via.placeholder.com/347x186" />
  160. <SectionHeading title="视频号ID" size="sm"></SectionHeading>
  161. <div class="bg-[#f6f6f6] rounded-lg px-3.5 py-2.5">
  162. <wd-input
  163. v-model="form.videoNumber"
  164. placeholder="请输入视频号ID"
  165. no-border
  166. custom-class="bg-[#f6f6f6]!"
  167. ></wd-input>
  168. </div>
  169. <BottomAppBar fixed :border="false">
  170. <div>
  171. <div class="text-center mb-5.5">
  172. <span class="text-black/40 text-xs font-normal font-['PingFang_SC'] leading-tight">
  173. 点击确认关联即表示同意
  174. </span>
  175. <span class="text-[#0cbe7c] text-xs font-normal font-['PingFang_SC'] leading-tight">
  176. 《个人微信视频号授权使用协议》
  177. </span>
  178. </div>
  179. <wd-button :round="false" block :loading="loading" @click="handleSubmit">
  180. 确定关联
  181. </wd-button>
  182. </div>
  183. </BottomAppBar> -->
  184. </div>
  185. </template>