makeMusicDetail.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. <template>
  2. <view class="make-music-detail">
  3. <!-- 顶部导航 -->
  4. <!-- <view class="nav-bar">
  5. <view class="left">
  6. <view class="uni-btn-icon" @click="goBack">&#xe601;</view>
  7. </view>
  8. <view class="center">音乐制作</view>
  9. <view class="right">
  10. <view class="coinM">
  11. <image src="/static/icon/coin_m.png" mode="aspectFit"></image>
  12. <text>{{ myinfo.num_gmm }}</text>
  13. </view>
  14. <view class="coinC">
  15. <image src="/static/icon/coin_cd.png" mode="aspectFit"></image>
  16. <text>{{ myinfo.num_gmd }}</text>
  17. </view>
  18. </view>
  19. </view> -->
  20. <!-- 顶部导航 -->
  21. <view class="nav-bar">
  22. <view class="left">
  23. <view class="uni-btn-icon" @click="goBack">&#xe601;</view>
  24. <view class="create">音乐制作</view>
  25. <image src="@/static/makedetail/cz_icon_lingganchuangzuo.png" class="edit"></image>
  26. </view>
  27. <view class="right">
  28. <view class="coinM">
  29. <image src="/static/icon/coin_m.png" mode="aspectFit"></image>
  30. <text>{{ myinfo.num_gmm }}</text>
  31. </view>
  32. <view class="coinC">
  33. <image src="/static/icon/coin_cd.png" mode="aspectFit"></image>
  34. <text>{{ myinfo.num_gmd }}</text>
  35. </view>
  36. </view>
  37. </view>
  38. <!-- 队列状态显示
  39. <view class="preview-section" v-if="inQueue">
  40. <view class="preview-card">
  41. <image class="loading-icon" src="/static/loading.png" mode="aspectFit"></image>
  42. <text class="loading-text">{{queueMessage}}</text>
  43. <text class="sub-text">请耐心等待制作完成</text>
  44. </view>
  45. </view> -->
  46. <!-- 排队预览区域 -->
  47. <view class="preview-section lineUp-section" v-if="queuing">
  48. <view class="section-title">
  49. <text>创作预览</text>
  50. <view class="member-box">
  51. <image src="@/static/makedetail/wd_icon_vip(1).png" mode="aspectFit"></image>
  52. 升级会员插队加速
  53. </view>
  54. </view>
  55. <view class="preview-card">
  56. <image src="@/static/makedetail/cz_icon_jiazai.png" mode="aspectFit"></image>
  57. <view class="text1">{{ queueMessage }}</view>
  58. <view class="text2">退出不影响继续生成</view>
  59. </view>
  60. </view>
  61. <!-- 创作预览区域 -->
  62. <view class="preview-section" v-if="inQueue">
  63. <view class="section-title">创作预览</view>
  64. <view class="preview-card">
  65. <image src="@/static/makedetail/cz_icon_shengcheng.png" mode="aspectFit"></image>
  66. <view class="text1">生成中0%</view>
  67. <view class="text2">退出不影响继续生成</view>
  68. </view>
  69. </view>
  70. <!-- 主要内容区 -->
  71. <view class="content">
  72. <!-- 歌曲名称输入 -->
  73. <view class="input-section">
  74. <text class="label">歌曲名称</text>
  75. <input type="text" placeholder="请输入名称..." class="input-field" maxlength="30" v-model="songName"
  76. :disabled="doYouWantToEdit()" />
  77. <text class="count lyricCount">{{ songName.length }}/30</text>
  78. </view>
  79. <!-- 创作歌词输入 -->
  80. <view class="input-section">
  81. <text class="label">创作歌词</text>
  82. <textarea placeholder="请在此处输入您想要进行联想的内容或者歌词" class="textarea-field" maxlength="800" v-model="lyrics"
  83. :disabled="doYouWantToEdit()" :style="{ height: textareaHeight + 'px' }" @input="onTextareaInput" />
  84. <view class="textarea-footer">
  85. <text class="count">{{ lyrics.length }}/800</text>
  86. <text class="ai-btn" v-if="false">
  87. <image src="@/static/makedetail/cz_btn_airunse.png"></image>
  88. </text>
  89. </view>
  90. </view>
  91. <!-- 音乐风格选择 -->
  92. <view class="style-section">
  93. <text class="label">音乐风格</text>
  94. <view class="tabs">
  95. <text :class="{ 'active': selectedTab === 'emotion' }" @click="selectTab('emotion')">
  96. 情感
  97. <view class="indicator-triangle">
  98. </view>
  99. </text>
  100. <text :class="{ 'active': selectedTab === 'genre' }" @click="selectTab('genre')">
  101. 流派
  102. <view class="indicator-triangle">
  103. </view>
  104. </text>
  105. <text :class="{ 'active': selectedTab === 'era' }" @click="selectTab('era')">
  106. 年代
  107. <view class="indicator-triangle">
  108. </view>
  109. </text>
  110. <text :class="{ 'active': selectedTab === 'instrument' }" @click="selectTab('instrument')">
  111. 乐器
  112. <view class="indicator-triangle">
  113. </view>
  114. </text>
  115. </view>
  116. <view class="tags">
  117. <text v-for="(tag, index) in currentTags" :key="index"
  118. :class="['tag', { active: selectedTags[selectedTab].includes(tag) }]"
  119. @click="doYouWantToEdit() ? state() : toggleTag(tag)">
  120. {{ tag }}
  121. </text>
  122. </view>
  123. </view>
  124. </view>
  125. <!-- 底部按钮 -->
  126. <view class="bottom-button">
  127. <button v-if="doYouWantToEdit" class="generate-btn" @click="generateMusic">立即生成
  128. <image src="/static/icon/coin_cd.png" mode="aspectFit"></image>
  129. 10
  130. </button>
  131. <view v-else class="generate-btn prohibit">生成中 </view>
  132. <view class="promotion-link">
  133. <image class="vip" src="/static/makedetail/wd_icon_vip(1).png" mode="aspectFit"></image>
  134. <text> 即刻开通订阅,获取各种福利! </text>
  135. <image class="jiantou" src="/static/makedetail/cz_icon_jiantou.png" mode="aspectFit"></image>
  136. </view>
  137. </view>
  138. </view>
  139. </template>
  140. <script>
  141. export default {
  142. name: 'MakeMusicDetail',
  143. data() {
  144. return {
  145. songName: '',
  146. lyrics: '',
  147. selectedTags: {
  148. emotion: [],
  149. genre: [],
  150. era: [],
  151. instrument: []
  152. },
  153. textareaHeight: 120,
  154. minHeight: 120,
  155. selectedTab: 'emotion',
  156. tagOptions: {
  157. emotion: ['欢快', '悲伤', '积极', '浪漫', '忧郁', '华丽', '闪耀', '神秘', '惊怒', '紧张', '恐怖', '平静'],
  158. genre: ['流行', '摇滚', '民谣', '电子', 'R&B', '嘻哈', '古典', '爵士'],
  159. era: ['80年代', '90年代', '00年代', '10年代', '20年代'],
  160. instrument: ['钢琴', '吉他', '贝斯', '鼓', '小提琴', '萨克斯', '电子合成器']
  161. },
  162. inQueue: false,//是否创作中
  163. queuing: false,//是否排队中
  164. queueMessage: '',
  165. myinfo: {}
  166. }
  167. },
  168. onLoad(e) {
  169. // this.checkQueueStatus();
  170. this.getMyInfo();
  171. if (e.id) {
  172. this.getQueueDetail(e.id)
  173. }
  174. },
  175. computed: {
  176. currentTags() {
  177. return this.selectedTab ? this.tagOptions[this.selectedTab] : [];
  178. }
  179. },
  180. methods: {
  181. doYouWantToEdit() {
  182. return this.inQueue || this.queuing
  183. },
  184. goBack() {
  185. uni.navigateBack({
  186. delta: 1
  187. });
  188. },
  189. getMyInfo() {
  190. uni.request({
  191. url: this.$apiHost + '/My/getnum',
  192. method: 'GET',
  193. header: {
  194. 'content-type': 'application/json',
  195. 'sign': getApp().globalData.headerSign
  196. },
  197. data: {
  198. uuid: getApp().globalData.uuid
  199. },
  200. success: (res) => {
  201. console.log("获取用户信息:", res.data);
  202. this.myinfo = res.data
  203. }
  204. })
  205. },
  206. checkQueueStatus() {
  207. uni.request({
  208. url: this.$apiHost + '/WorkAI/queueStatus',
  209. method: 'GET',
  210. header: {
  211. 'content-type': 'application/json',
  212. 'sign': getApp().globalData.headerSign
  213. },
  214. data: {
  215. uuid: getApp().globalData.uuid,
  216. task_type: 2
  217. },
  218. success: (res) => {
  219. console.log("音乐队列状态:", res.data);
  220. if (res.data.success === "yes") {
  221. this.inQueue = res.data.in_queue
  222. if (this.inQueue) {
  223. this.queueMessage = res.data.str
  224. }
  225. }
  226. },
  227. fail: (err) => {
  228. console.log('获取队列状态失败:', err);
  229. uni.showToast({
  230. title: '获取状态失败',
  231. icon: 'none'
  232. });
  233. }
  234. })
  235. this.getMyInfo();
  236. },
  237. generateMusic() {
  238. if (!this.songName.trim()) {
  239. uni.showToast({
  240. title: '请输入歌曲名称',
  241. icon: 'none'
  242. })
  243. return
  244. }
  245. if (!this.lyrics.trim()) {
  246. uni.showToast({
  247. title: '请输入歌词内容',
  248. icon: 'none'
  249. })
  250. return
  251. }
  252. // 合并所有选中的标签
  253. let allSelectedTags = [
  254. ...this.selectedTags.emotion,
  255. ...this.selectedTags.genre,
  256. ...this.selectedTags.era,
  257. ...this.selectedTags.instrument
  258. ];
  259. console.log(this.lyrics, this.songName,);
  260. let that = this
  261. uni.request({
  262. url: this.$apiHost + '/WorkAI/creatorMusic',
  263. data: {
  264. uuid: getApp().globalData.uuid,
  265. name: this.songName,
  266. lyrics: this.lyrics,
  267. style: allSelectedTags.join(',')
  268. },
  269. method: 'POST',
  270. header: {
  271. 'Content-Type': 'application/x-www-form-urlencoded',
  272. 'sign': getApp().globalData.headerSign
  273. },
  274. dataType: 'json',
  275. success: (res) => {
  276. console.log("生成结果:", res.data);
  277. uni.showToast({
  278. title: res.data.str || '请求成功',
  279. icon: 'none'
  280. });
  281. if (res.data.success == "yes") {
  282. setTimeout(function () {
  283. // that.checkQueueStatus()
  284. //返回上一页
  285. uni.navigateBack()
  286. }, 500);
  287. }
  288. },
  289. fail: (err) => {
  290. console.log('生成失败:', err);
  291. uni.showToast({
  292. title: '生成请求失败',
  293. icon: 'none'
  294. });
  295. }
  296. })
  297. },
  298. onTextareaInput(e) {
  299. const lineHeight = 20; // 假设每行高度为20px
  300. const padding = 30; // 上下padding各15px
  301. const value = e.detail.value;
  302. const lines = value.split('\n').length;
  303. // 计算每行的平均字符数
  304. const avgCharsPerLine = 30; // 根据实际输入框宽度调整
  305. const textLines = Math.ceil(value.length / avgCharsPerLine);
  306. // 取行数的最大值,确保有足够空间显示
  307. const totalLines = Math.max(lines, textLines);
  308. const newHeight = Math.max(totalLines * lineHeight + padding, this.minHeight);
  309. this.textareaHeight = newHeight;
  310. },
  311. selectTab(tab) {
  312. if (this.selectedTab !== tab) {
  313. this.selectedTab = tab;
  314. // 不再清空已选择的标签
  315. }
  316. },
  317. state() {
  318. if (this.inQueue) {
  319. uni.showToast({
  320. title: '正在创作中无法修改',
  321. icon: 'none'
  322. })
  323. } else if (this.queuing) {
  324. uni.showToast({
  325. title: '正在排队中无法修改',
  326. icon: 'none'
  327. })
  328. }
  329. },
  330. toggleTag(tag) {
  331. if (this.selectedTags[this.selectedTab].includes(tag)) {
  332. this.selectedTags[this.selectedTab] = this.selectedTags[this.selectedTab].filter(t => t !== tag);
  333. } else {
  334. this.selectedTags[this.selectedTab].push(tag);
  335. }
  336. },
  337. getQueueDetail(id) {
  338. if (!id) {
  339. return
  340. }
  341. let that = this
  342. uni.request({
  343. url: this.$apiHost + '/WorkAI/getQueueDetail',
  344. data: {
  345. uuid: getApp().globalData.uuid,
  346. id: id
  347. },
  348. header: {
  349. 'Content-Type': 'application/x-www-form-urlencoded',
  350. 'sign': getApp().globalData.headerSign
  351. },
  352. dataType: 'json',
  353. success: (res) => {
  354. console.log("查询单个结果:", res.data);
  355. if (res.data.success == "yes") {
  356. var { queuePosition, allPosition, song_name,lyrics,style} = res.data.data
  357. that.songName=song_name
  358. that.lyrics =lyrics
  359. const styles = style.split(',');
  360. styles.forEach(tag => {
  361. for (const [key, tags] of Object.entries(that.tagOptions)) {
  362. if (tags.includes(tag)) {
  363. that.selectedTags[key].push(tag);
  364. break;
  365. }
  366. }
  367. });
  368. if (queuePosition == allPosition) {
  369. // 创作中逻辑
  370. that.inQueue = true
  371. } else if (queuePosition < allPosition) {
  372. // 排队中逻辑
  373. that.queuing = true
  374. }
  375. }
  376. },
  377. fail: (err) => {
  378. console.log('查询失败失败:', err);
  379. uni.showToast({
  380. title: '查询失败请求失败',
  381. icon: 'none'
  382. });
  383. }
  384. })
  385. }
  386. }
  387. }
  388. </script>
  389. <style lang="scss">
  390. @import './makeMusicDetail.scss';
  391. </style>