index.js 10 KB

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