index.js 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. import {
  2. getActivityInfo,
  3. saveActivity
  4. } from '~/api/activity'
  5. /*微信录音*/
  6. let recorderManager = wx.getRecorderManager();
  7. let dsq
  8. Page({
  9. /**
  10. * 页面的初始数据
  11. */
  12. data: {
  13. // 'before录制前, process 录制中,after录制后'
  14. state: 'before',
  15. tens: 3,
  16. bits: 0,
  17. fromWidth: 100,
  18. toWidth: 100,
  19. configure: {},
  20. avatar: '',
  21. // 本地录音地址
  22. tempFilePath: '',
  23. // 线上录音地址
  24. audioPath: '',
  25. uploadState: false,
  26. // 此id保存模板使用
  27. id: '',
  28. greeting: [],
  29. // 是否更改过头像
  30. changeAvatarFlag: false,
  31. greetingCard: null,
  32. userAudioState: false,
  33. // 当前音频播放时长
  34. playTime: '00:00',
  35. endTime: '00:00',
  36. vProgress: 0
  37. },
  38. async onLoad(options) {
  39. let configure = await getActivityInfo(options.id)
  40. wx.setNavigationBarTitle({
  41. title: configure.title,
  42. })
  43. this.setData({
  44. configure,
  45. avatar: configure.photoText,
  46. toWidth: '',
  47. fromWidth: configure.fromText.length * configure.fromFontSize,
  48. toWidth: configure.toText.length * configure.toFontSize,
  49. id: options.id,
  50. greeting: configure.greeting.split('\r'),
  51. tens: configure.bgMusicLength[0],
  52. bits: configure.bgMusicLength[1]
  53. })
  54. },
  55. async changeAvatar(e) {
  56. const {
  57. avatarUrl
  58. } = e.detail
  59. let res = await this.uploadFile(avatarUrl)
  60. this.setData({
  61. changeAvatarFlag: true,
  62. avatar: res
  63. })
  64. },
  65. play() {
  66. if (this.data.state == 'before') {
  67. this.innerAudioContext = wx.createInnerAudioContext();
  68. this.innerAudioContext.src = this.data.configure.bgMusic; // 这里可以是录音的临时路径
  69. this.innerAudioContext.play();
  70. this.innerAudioContext.onEnded((res) => {
  71. console.log('音频播放完毕');
  72. this.setData({
  73. userAudioState: false
  74. })
  75. });
  76. this.setData({
  77. state: 'process'
  78. })
  79. let countDown = Number(this.data.configure.bgMusicLength)
  80. // 倒计时
  81. this.dsq = setInterval(item => {
  82. console.log('仍然倒计时呢');
  83. // 倒计时结束
  84. if (countDown == 1) {
  85. this.stopRecording()
  86. }
  87. if (countDown % 10 == 0) {
  88. this.setData({
  89. tens: --this.data.tens,
  90. bits: 9
  91. })
  92. } else {
  93. this.setData({
  94. bits: --this.data.bits
  95. })
  96. }
  97. --countDown
  98. }, 1000)
  99. const options = {
  100. sampleRate: 44100, //采样率
  101. numberOfChannels: 1, //录音通道数
  102. encodeBitRate: 192000, //编码码率
  103. format: 'mp3', //音频格式,有效值aac/mp3
  104. frameSize: 50 //指定帧大小,单位 KB
  105. };
  106. //开始录音,在开始录音回调中feed音频片
  107. recorderManager.start(options);
  108. //监听录音结束事件
  109. recorderManager.onStop((res) => {
  110. this.setData({
  111. tempFilePath: res.tempFilePath,
  112. });
  113. this.uploadAudio(res.tempFilePath)
  114. });
  115. } else {
  116. this.stopRecording()
  117. }
  118. },
  119. stopRecording() {
  120. clearInterval(this.dsq)
  121. this.innerAudioContext.stop();
  122. recorderManager.stop();
  123. this.setData({
  124. state: 'after',
  125. tens: this.data.configure.bgMusicLength[0],
  126. bits: this.data.configure.bgMusicLength[1]
  127. })
  128. },
  129. uploadAudio(recordSource) {
  130. this.setData({
  131. uploadState: true
  132. });
  133. const uploadTask = wx.uploadFile({
  134. url: 'https://reader-api.ai160.com//file/upload',
  135. filePath: recordSource,
  136. name: '朗读录音',
  137. header: {
  138. uid: wx.getStorageSync('uid')
  139. },
  140. success: (res) => {
  141. const formateRes = JSON.parse(res.data);
  142. let audioPath = formateRes.data;
  143. this.setData({
  144. audioPath
  145. })
  146. this.uploadActivity()
  147. },
  148. })
  149. },
  150. // 上传贺卡
  151. async uploadActivity() {
  152. this.createActivityImg('upload').then(async res => {
  153. let cardUrl = await this.uploadFile(res)
  154. let data = {
  155. audioPath: this.data.audioPath,
  156. // 生成贺卡图片地址
  157. cardUrl,
  158. toText: this.data.configure.toText,
  159. fromText: this.data.configure.fromText,
  160. templateId: this.data.id
  161. }
  162. console.log(data, 'data');
  163. let greetingCard = await saveActivity(data)
  164. console.log('贺卡生成', greetingCard);
  165. this.setDuration('endTime', greetingCard.duration)
  166. this.setData({
  167. greetingCard,
  168. uploadState: false
  169. })
  170. })
  171. },
  172. playUserAudio() {
  173. if (!this.innerAudioContext) {
  174. this.innerAudioContext = wx.createInnerAudioContext();
  175. }
  176. if (this.data.userAudioState) {
  177. this.innerAudioContext.stop();
  178. this.setData({
  179. userAudioState: false
  180. })
  181. } else {
  182. this.innerAudioContext.src = this.data.greetingCard.audioPath;
  183. this.innerAudioContext.onTimeUpdate(() => {
  184. this.setDuration('playTime', this.innerAudioContext.currentTime)
  185. this.setData({
  186. vProgress: Math.ceil((Math.ceil(this.innerAudioContext.currentTime) / this.innerAudioContext.duration) * 100)
  187. })
  188. })
  189. this.innerAudioContext.play();
  190. this.setData({
  191. userAudioState: true
  192. })
  193. }
  194. },
  195. bindKeyInput(e) {
  196. if (e.currentTarget.dataset.type == 'from') {
  197. this.setData({
  198. fromWidth: e.detail.cursor * this.data.configure.fromFontSize,
  199. 'configure.fromText': e.detail.value
  200. })
  201. } else if (e.currentTarget.dataset.type == 'to') {
  202. this.setData({
  203. toWidth: e.detail.cursor * this.data.configure.toFontSize,
  204. 'configure.toText': e.detail.value
  205. })
  206. }
  207. },
  208. // 上传图片
  209. uploadFile(filePath) {
  210. return new Promise((resolve, reject) => {
  211. wx.uploadFile({
  212. url: 'https://reader-api.ai160.com/file/upload',
  213. filePath,
  214. name: '头像',
  215. header: {
  216. uid: wx.getStorageSync('uid')
  217. },
  218. success: (res) => {
  219. const result = JSON.parse(res.data).data;
  220. resolve(result)
  221. }
  222. })
  223. })
  224. },
  225. // 生成活动图片
  226. createActivityImg(createType = 'share') {
  227. return new Promise((resolve, reject) => {
  228. let cardUrl = !this.data.greetingCard ? '' : this.data.greetingCard.cardUrl
  229. if (cardUrl) {
  230. resolve({
  231. title: '请欣赏我的课文朗读作品,点赞+评论。',
  232. path: `/pages/index/index`,
  233. imageUrl: cardUrl
  234. })
  235. }
  236. let context = wx.createSelectorQuery();
  237. context
  238. .select('#share')
  239. .fields({
  240. node: true,
  241. size: true
  242. }).exec((res) => {
  243. const canvas = res[0].node;
  244. const ctx = canvas.getContext('2d');
  245. const dpr = wx.getSystemInfoSync().pixelRatio;
  246. canvas.width = res[0].width * dpr;
  247. canvas.height = res[0].height * dpr;
  248. ctx.scale(dpr, dpr);
  249. let avatar = canvas.createImage();
  250. avatar.src = this.data.avatar
  251. avatar.onload = () => {
  252. ctx.drawImage(avatar, this.data.configure.templateBase.photoLeft / 2, this.data.configure.templateBase.photoTop / 2, this.data.configure.templateBase.photoWidth / 2, this.data.configure.templateBase.photoHeight / 2);
  253. let bgImg = canvas.createImage();
  254. bgImg.src = this.data.configure.bgImg
  255. bgImg.onload = () => {
  256. ctx.drawImage(bgImg, 0, 0, 375, 300);
  257. ctx.font = `${this.data.configure.fromFontSize/2}px PingFang`;
  258. ctx.fillText(this.data.configure.toText, this.data.configure.templateBase.toLeft / 2, this.data.configure.templateBase.toTop / 2 + this.data.configure.fromFontSize / 2)
  259. ctx.fillText(this.data.configure.fromText, this.data.configure.templateBase.fromLeft / 2, this.data.configure.templateBase.fromTop / 2 + this.data.configure.toFontSize / 2)
  260. console.log(this.data.configure.toText, this.data.configure.templateBase.toLeft / 2, this.data.configure.templateBase.toTop / 2);
  261. console.log(this.data.configure.fromText, this.data.configure.templateBase.fromLeft / 2, this.data.configure.templateBase.fromTop / 2);
  262. setTimeout(() => {
  263. wx.canvasToTempFilePath({
  264. canvas: canvas,
  265. success(res) {
  266. if (createType == 'share') {
  267. resolve({
  268. title: '请欣赏我的课文朗读作品,点赞+评论。',
  269. path: `/pages/index/index`,
  270. imageUrl: res.tempFilePath
  271. })
  272. } else {
  273. resolve(res.tempFilePath)
  274. }
  275. },
  276. fail(res) {
  277. reject()
  278. }
  279. }, this)
  280. }, 1000)
  281. }
  282. }
  283. })
  284. })
  285. },
  286. onShareAppMessage({
  287. from,
  288. }) {
  289. if (from == 'button') {
  290. const promise = new Promise(resolve => {
  291. this.createActivityImg().then(res => {
  292. resolve(res)
  293. })
  294. })
  295. return {
  296. title: '请欣赏我的课文朗读作品,点赞+评论。',
  297. path: `/pages/index/index?&uid=${wx.getStorageSync('uid')}`,
  298. imageUrl: 'http://reader-wx.ai160.com/images/reader/v3/shareContent.png',
  299. promise
  300. }
  301. } else {
  302. return {
  303. title: '课文朗读,从未如此有趣。',
  304. path: `/pages/index/index?&uid=${wx.getStorageSync('uid')}`,
  305. imageUrl: 'http://reader-wx.ai160.com/images/reader/v3/shareContent.png'
  306. }
  307. }
  308. },
  309. // 设置时间文案
  310. setDuration(label, s) {
  311. let t = '';
  312. s = Math.ceil(s);
  313. if (s > -1) {
  314. let min = Math.floor(s / 60) % 60;
  315. let sec = s % 60;
  316. if (min < 10) {
  317. t += "0";
  318. }
  319. t += min + ":";
  320. if (sec < 10) {
  321. t += "0";
  322. }
  323. t += sec;
  324. }
  325. this.setData({
  326. [label]: t,
  327. })
  328. },
  329. onHide() {
  330. recorderManager.stop()
  331. this.innerAudioContext.stop()
  332. }
  333. })