zhuantiInfo.vue 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. <template>
  2. <view class="ezy-biaoqing-page">
  3. <view class="ezy-nav-bar-icon" @click="goUpPage"></view>
  4. <view class="biaoqing-bj-box" :class="'biaoqing-bj'+ type">
  5. <view v-for="(item, index) in bubbles" :key="index" class="qipao-item-box"
  6. :class="{ 'qipao-item-disabled': item.disabled }" @click="qipaoBtn(index)">
  7. <view v-if="item.showFlag ==1">
  8. <view :class="item.iconType"></view>
  9. <view class="show-biaoqing-icon"></view>
  10. <view class="qipao-text-row">
  11. <text>可扎破</text>
  12. <icon class="shou-icon"></icon>
  13. </view>
  14. </view>
  15. </view>
  16. <view class="biaoqing-img"></view>
  17. </view>
  18. <view :class="maikeType">
  19. <view class="maike-box" @touchstart="handleTouchStart" @touchend="handleTouchEnd"
  20. @touchcancel="handleTouchCancel" @touchmove="handleTouchMove">
  21. <icon class="maike-icon"></icon>
  22. </view>
  23. <text class="maike-text" v-if="maikeType =='maike-anzhu'">{{ buttonText }}</text>
  24. <text class="maike-text" v-if="maikeType =='maike-songkai'">{{ buttonText }}</text>
  25. </view>
  26. <CustomTabBar :currentTabNumber="1"></CustomTabBar>
  27. </view>
  28. </template>
  29. <script setup>
  30. import {
  31. toast,
  32. getUserIdentity
  33. } from "@/utils/common";
  34. import cacheManager from '@/utils/cacheManager.js';
  35. import {
  36. moodAdd,
  37. moodLess,
  38. moodSize
  39. } from '@/api/zhuanti.js'
  40. import CustomTabBar from '@/components/custom-tabbar/custom-tabbar.vue';
  41. import {
  42. reactive,
  43. ref,
  44. computed,
  45. onBeforeUnmount
  46. } from "vue";
  47. import {
  48. onLoad
  49. } from '@dcloudio/uni-app';
  50. const maikeType = ref('maike-anzhu');
  51. // 定义气泡数据状态
  52. // const bubbles = reactive(
  53. // // Array.from({
  54. // // length: 5
  55. // // }, () => ({
  56. // // disabled: false, // 是否破裂
  57. // // iconType: "qipao-mask", //mask
  58. // // }))
  59. // );
  60. let bubbles = ref([])
  61. const type = ref(null);
  62. const audioContext = ref(null);
  63. const audioPath = '/static/mp3/zhuanti/qipao.mp3';
  64. const isPlaying = ref(false);
  65. const showIcon = ref(null);
  66. const isPressing = ref(false); // 是否正在按压
  67. const isCancelled = ref(false); // 是否已取消
  68. const touchPos = ref({
  69. x: 0,
  70. y: 0
  71. }); // 触摸位置
  72. onLoad((options) => {
  73. console.log('opt', options);
  74. type.value = options.type
  75. getSize()
  76. initAudio()
  77. })
  78. function initAudio() {
  79. audioContext.value = uni.createInnerAudioContext();
  80. audioContext.value.src = audioPath;
  81. // 设置事件监听
  82. audioContext.value.onPlay(() => {
  83. console.log('开始播放');
  84. isPlaying.value = true;
  85. });
  86. audioContext.value.onPause(() => {
  87. console.log('暂停播放');
  88. isPlaying.value = false;
  89. });
  90. audioContext.value.onStop(() => {
  91. console.log('停止播放');
  92. isPlaying.value = false;
  93. });
  94. audioContext.value.onError((err) => {
  95. console.error('播放错误:', err);
  96. isPlaying.value = false;
  97. uni.showToast({
  98. title: '播放失败',
  99. icon: 'none'
  100. });
  101. });
  102. }
  103. function getSize() {
  104. moodSize({
  105. type: type.value
  106. }).then(res => {
  107. if (res.code == 0) {
  108. bubbles.value = Array.from({
  109. length: Number(res.data)
  110. }, () => ({
  111. disabled: false,
  112. iconType: "qipao-mask",
  113. showFlag: "1",
  114. }));
  115. } else {
  116. toast("查询数量失败")
  117. return false
  118. }
  119. })
  120. }
  121. // 点击气泡
  122. function qipaoBtn(index) {
  123. moodLess({
  124. type: type.value
  125. }).then(res => {
  126. if (res.code == 0) {
  127. if (isPlaying.value) {
  128. audioContext.value.stop();
  129. } else {
  130. audioContext.value.play(); // 开始播放
  131. }
  132. bubbles.value[index].disabled = true;
  133. bubbles.value[index].iconType = "polie-qipao-mask";
  134. setTimeout(() => {
  135. bubbles.value[index] = {};
  136. }, 200)
  137. // setTimeout(() => {
  138. // bubbles.value.splice(index, 1)
  139. // }, 1000)
  140. } else {
  141. toast("戳破气泡失败!")
  142. return false
  143. }
  144. })
  145. // wgy看这↓ 在这里播放mp3,时间一秒及删除接口
  146. }
  147. // const buttonState = computed(() => {
  148. // if (isCancelled.value) return 'cancelled';
  149. // return isPressing.value ? 'recording' : 'idle';
  150. // });
  151. // const showCancel = computed(() => {
  152. // return isPressing.value && !isCancelled.value;
  153. // });
  154. const buttonText = computed(() => {
  155. if (isCancelled.value) return '松开取消';
  156. return isPressing.value ? '松开发送' : '按住说话';
  157. });
  158. const handleTouchStart = (e) => {
  159. isPressing.value = true;
  160. isCancelled.value = false;
  161. touchPos.value = {
  162. x: e.touches[0].clientX,
  163. y: e.touches[0].clientY
  164. };
  165. // 这里触发开始逻辑(如开始录音)
  166. console.log('操作开始');
  167. maikeType.value = 'maike-songkai';
  168. };
  169. const handleTouchEnd = () => {
  170. if (isPressing.value && !isCancelled.value) {
  171. console.log('操作完成');
  172. const newLength = bubbles.value.filter(item =>
  173. Object.keys(item).length > 0
  174. ).length;
  175. if (newLength == 5) {
  176. console.log('5555');
  177. maikeType.value = 'maike-anzhu';
  178. resetState();
  179. return false
  180. }
  181. moodAdd({
  182. type: type.value
  183. }).then(res => {
  184. console.log('moodAdd', res);
  185. const array = {
  186. disabled: false,
  187. iconType: "qipao-mask",
  188. showFlag: "1",
  189. }
  190. addItem(array)
  191. //bubbles.value.push(array)
  192. })
  193. }
  194. console.log('bubbles', bubbles.value);
  195. maikeType.value = 'maike-anzhu';
  196. resetState();
  197. };
  198. function addItem(item) {
  199. const emptyIndex = bubbles.value.findIndex(item =>
  200. Object.keys(item).length == 0
  201. );
  202. if (emptyIndex !== -1) {
  203. // 如果找到空对象,替换它
  204. bubbles.value[emptyIndex] = item;
  205. } else {
  206. // 如果没有空对象,推入新项
  207. bubbles.value.push(item);
  208. }
  209. return bubbles.value;
  210. }
  211. const handleTouchCancel = () => {
  212. isCancelled.value = true;
  213. maikeType.value = 'maike-songkai';
  214. resetState();
  215. console.log('操作取消');
  216. };
  217. const handleTouchMove = (e) => {
  218. if (!isPressing.value) return;
  219. // 计算二维平面上两点之间直线距离
  220. const currentX = e.touches[0].clientX;
  221. const currentY = e.touches[0].clientY;
  222. const moveDistance = Math.sqrt(
  223. Math.pow(currentX - touchPos.value.x, 2) +
  224. Math.pow(currentY - touchPos.value.y, 2)
  225. );
  226. if (moveDistance > 50) {
  227. isCancelled.value = true;
  228. } else if (isCancelled.value && moveDistance <= 50) {
  229. isCancelled.value = false;
  230. }
  231. };
  232. const resetState = () => {
  233. isPressing.value = false;
  234. setTimeout(() => {
  235. isCancelled.value = false;
  236. }, 500); // 短暂保持
  237. };
  238. function goUpPage() {
  239. uni.redirectTo({
  240. url: `/pages/zhuanti/index`
  241. })
  242. }
  243. </script>