makeDetail.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681
  1. <template>
  2. <view class="page">
  3. <!-- 引入FontAwesome -->
  4. <view>
  5. <link rel="stylesheet"
  6. href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
  7. </view>
  8. <!-- 顶部导航栏 -->
  9. <view class="custom-navbar">
  10. <view class="navbar-left" @click="goBack">
  11. <text class="fa fa-angle-left"></text>
  12. </view>
  13. <view class="navbar-center">
  14. <view class="navbar-title">
  15. <image class="navbar-avatar" :src="myinfo.avatar" mode="aspectFill"></image>
  16. <text class="navbar-text">{{ myinfo.nickname }}</text>
  17. <text class="navbar-badge" v-if="myinfo.is_vip > 0">VIP</text>
  18. </view>
  19. </view>
  20. <view class="navbar-right" @click="showActionSheet">
  21. <text class="fa fa-ellipsis-h"></text>
  22. </view>
  23. </view>
  24. <!-- 内容头图区域 -->
  25. <view class="topUser">
  26. <image :src="home_image" class="home_image" mode="aspectFill"></image>
  27. <!-- 图片指示器 -->
  28. <!-- <view class="image-indicator" v-if="image_list.length > 1">
  29. <text>{{ selImg + 1 }}/{{ image_list.length }}</text>
  30. </view> -->
  31. <!-- 音乐类型时显示歌词 -->
  32. <view class="lyrics-overlay" v-if="queueDetail.task_type == 2" @mousedown="startDrag" @mouseup="stopDrag"
  33. @mousemove="drag">
  34. <text class="lyrics-text" ref="lyricsText"
  35. :style="{ transform: `translateY(${offsetY}px)` }">{{ queueDetail.description }}</text>
  36. </view>
  37. <!-- 音乐类型且状态为9时显示播放按钮 -->
  38. <view class="play-button" v-if="queueDetail.task_type == 2 && queueDetail.status >= 9" @click="toggleAudio">
  39. <text class="fa" :class="isPlaying ? 'fa-pause' : 'fa-play'"></text>
  40. </view>
  41. </view>
  42. <view class="body">
  43. <view class="article-header">
  44. <text class="title">{{ queueDetail.title }}</text>
  45. <view class="meta-info">
  46. <view class="meta-item">
  47. <text class="fa fa-clock-o"></text>
  48. <text class="meta-text">{{ queueDetail.create_time }}</text>
  49. </view>
  50. <view class="meta-item">
  51. <text class="fa fa-tag"></text>
  52. <text class="meta-text">{{ queueDetail.task_type == 1 ? '灵感创作' : '音乐创作' }}</text>
  53. </view>
  54. <view class="meta-item">
  55. <text class="fa fa-circle" :style="getStatusStyle(queueDetail.status)"></text>
  56. <text class="meta-text">{{ getStatusText(queueDetail.status) }}</text>
  57. </view>
  58. </view>
  59. </view>
  60. <view class="divider"></view>
  61. <view class="article-content">
  62. <!-- 灵感创作显示description -->
  63. <view v-if="queueDetail.task_type == 1">
  64. <text class="content">{{ queueDetail.description }}</text>
  65. </view>
  66. <!-- 音乐创作显示lyrics -->
  67. <view v-if="queueDetail.task_type == 2">
  68. <text class="content">{{ queueDetail.lyrics }}</text>
  69. </view>
  70. <!-- 显示创作详情 -->
  71. <view class="creation-details" v-if="queueDetail.task_type == 1">
  72. <view class="detail-item" v-if="queueDetail.action">
  73. <text class="detail-label">行为动作:</text>
  74. <text class="detail-value">{{ queueDetail.action }}</text>
  75. </view>
  76. <view class="detail-item" v-if="queueDetail.environment">
  77. <text class="detail-label">主体环境:</text>
  78. <text class="detail-value">{{ queueDetail.environment }}</text>
  79. </view>
  80. <view class="detail-item" v-if="queueDetail.subject">
  81. <text class="detail-label">主体形象:</text>
  82. <text class="detail-value">{{ queueDetail.subject }}</text>
  83. </view>
  84. <view class="detail-item" v-if="queueDetail.style">
  85. <text class="detail-label">参考风格:</text>
  86. <text class="detail-value">{{ queueDetail.style }}</text>
  87. </view>
  88. </view>
  89. <!-- 音乐创作显示歌曲名称 -->
  90. <view class="creation-details" v-if="queueDetail.task_type == 2">
  91. <view class="detail-item" v-if="queueDetail.song_name">
  92. <text class="detail-label">歌曲名称:</text>
  93. <text class="detail-value">{{ queueDetail.song_name }}</text>
  94. </view>
  95. </view>
  96. <!-- 显示状态信息 -->
  97. <view class="status-info" v-if="queueDetail.status < 4">
  98. <view class="queue-info">
  99. <text class="queue-text">队列位置:
  100. {{ queueDetail.queue_position }}/{{ queueDetail.all_position }}</text>
  101. <view class="progress-bar">
  102. <view class="progress-fill" :style="{ width: getProgressWidth() }"></view>
  103. </view>
  104. </view>
  105. </view>
  106. <!-- 显示错误信息 -->
  107. <view class="error-message" v-if="queueDetail.status == 3">
  108. <text class="error-text">{{ queueDetail.error_msg }}</text>
  109. </view>
  110. </view>
  111. </view>
  112. <view class="thread2"></view>
  113. <!-- 音频元素 -->
  114. <audio id="audioPlayer" :src="queueDetail.result_audio" style="display:none;"></audio>
  115. <!-- 底部漂浮栏 -->
  116. <view class="floating-bar" v-if="queueDetail.status == 9">
  117. <view class="floating-bar-content">
  118. <view class="add-note-btn" @click="showAddNotePopup">
  119. <text>添加说明</text>
  120. </view>
  121. <view class="publish-btn" @click="publishWork">
  122. <text>公布作品</text>
  123. </view>
  124. </view>
  125. </view>
  126. <!-- 添加说明弹窗 -->
  127. <view class="popup-mask" v-if="showNotePopup" @click="closeAddNotePopup"></view>
  128. <view class="note-popup" v-if="showNotePopup">
  129. <view class="popup-header">
  130. <text class="popup-title">添加说明</text>
  131. </view>
  132. <view class="popup-content">
  133. <textarea class="note-textarea" v-model="noteContent" placeholder="请描述你想添加的内容。"
  134. maxlength="500"></textarea>
  135. <view class="word-count">{{noteContent.length}}/500</view>
  136. </view>
  137. <view class="popup-footer">
  138. <view class="cancel-btn" @click="closeAddNotePopup">
  139. <text>取消</text>
  140. </view>
  141. <view class="confirm-btn" @click="confirmAddNote">
  142. <text>确认</text>
  143. </view>
  144. </view>
  145. </view>
  146. </view>
  147. </template>
  148. <script>
  149. import previewImage from '@/components/kxj-previewImage/kxj-previewImage.vue'; //引用插件
  150. export default {
  151. components: {
  152. previewImage
  153. },
  154. data() {
  155. return {
  156. title: '',
  157. arcID: 0,
  158. selImg: 0,
  159. home_image: '',
  160. myinfo: {},
  161. tag_list: [],
  162. image_list: [],
  163. imgs: [],
  164. descs: [],
  165. isPlaying: false,
  166. audioPlayer: null,
  167. showNotePopup: false,
  168. noteContent: '',
  169. // 队列详情数据
  170. queueDetail: {
  171. id: 0,
  172. sso_id: 0,
  173. task_type: 1,
  174. title: '',
  175. description: '',
  176. action: '',
  177. environment: '',
  178. subject: '',
  179. style: '',
  180. song_name: '',
  181. lyrics: '',
  182. generate_uuid: '',
  183. result_images: '',
  184. result_audio: '',
  185. queue_position: 0,
  186. status: 1,
  187. generate_status: 1,
  188. points_cost: 0,
  189. error_msg: '',
  190. create_time: '',
  191. update_time: '',
  192. all_position: 0
  193. },
  194. myinfo: {},
  195. offsetY: 0,
  196. isDragging: false,
  197. startY: 0,
  198. initialOffsetY: 0
  199. }
  200. },
  201. onLoad(parms) {
  202. let self = this;
  203. this.arcID = parms.id || 3;
  204. this.getMyInfo();
  205. },
  206. onShow() {
  207. this.loadData();
  208. },
  209. onReady() {
  210. // 获取音频元素
  211. this.audioPlayer = uni.createInnerAudioContext();
  212. this.audioPlayer.onEnded(() => {
  213. this.isPlaying = false;
  214. });
  215. },
  216. onUnload() {
  217. // 页面卸载时停止音频播放
  218. if (this.audioPlayer) {
  219. this.audioPlayer.stop();
  220. this.audioPlayer.destroy();
  221. }
  222. },
  223. methods: {
  224. // 返回上一页
  225. goBack() {
  226. uni.navigateBack({
  227. delta: 1
  228. });
  229. },
  230. getMyInfo() {
  231. uni.request({
  232. url: this.$apiHost + '/My/getnum',
  233. method: 'GET',
  234. header: {
  235. 'content-type': 'application/json',
  236. 'sign': getApp().globalData.headerSign
  237. },
  238. data: {
  239. uuid: getApp().globalData.uuid
  240. },
  241. success: (res) => {
  242. console.log("获取用户信息:", res.data);
  243. this.myinfo = res.data
  244. }
  245. })
  246. },
  247. selPhoto(item, sel) {
  248. this.selImg = sel;
  249. this.home_image = this.image_list[sel];
  250. },
  251. toArr(imgs) {
  252. let arr = imgs.split("|");
  253. return arr;
  254. },
  255. previewOpen(imgs1, index) {
  256. this.imgs = imgs1.split("|");
  257. setTimeout(() => this.$refs.previewImage.open(index), 0)
  258. // 传入当前选中的图片地址或序号
  259. return; //如需测试和uni原生预览差别可注释这两行
  260. },
  261. // 切换音频播放状态
  262. toggleAudio() {
  263. if (!this.queueDetail.result_audio) return;
  264. if (this.isPlaying) {
  265. this.audioPlayer.pause();
  266. this.isPlaying = false;
  267. } else {
  268. this.audioPlayer.src = this.queueDetail.result_audio;
  269. this.audioPlayer.play();
  270. this.isPlaying = true;
  271. }
  272. },
  273. // 获取状态文本
  274. getStatusText(status) {
  275. const statusMap = {
  276. 1: '排队中',
  277. 2: '生成中',
  278. 3: '生成失败',
  279. 4: '已完成',
  280. 9: '已完成'
  281. };
  282. return statusMap[status] || '未知状态';
  283. },
  284. // 获取状态样式
  285. getStatusStyle(status) {
  286. const colorMap = {
  287. 1: '#ffa500', // 橙色 - 排队中
  288. 2: '#2979ff', // 蓝色 - 生成中
  289. 3: '#ff5151', // 红色 - 生成失败
  290. 4: '#4caf50', // 绿色 - 已完成
  291. 9: '#4caf50' // 绿色 - 已完成
  292. };
  293. return `color: ${colorMap[status] || '#999'}`;
  294. },
  295. // 获取进度条宽度
  296. getProgressWidth() {
  297. if (this.queueDetail.all_position === 0) return '0%';
  298. const progress = (1 - (this.queueDetail.queue_position / this.queueDetail.all_position)) * 100;
  299. return `${progress}%`;
  300. },
  301. // 加载数据
  302. loadData() {
  303. uni.showLoading({
  304. title: '加载中...'
  305. });
  306. uni.request({
  307. url: this.$apiHost + '/WorkAI/getQueueDetail',
  308. data: {
  309. uuid: getApp().globalData.uuid,
  310. id: this.arcID
  311. },
  312. header: {
  313. "content-type": "application/json",
  314. 'sign': getApp().globalData.headerSign
  315. },
  316. success: (res) => {
  317. console.log("队列详情:", res.data);
  318. if (res.data.success === "yes") {
  319. // 更新队列详情
  320. this.queueDetail = res.data.data;
  321. this.noteContent = res.data.data.content;
  322. // 更新图片列表
  323. if (this.queueDetail.result_images && this.queueDetail.result_images !== "") {
  324. this.image_list = this.queueDetail.result_images.split(",");
  325. this.home_image = this.image_list[0];
  326. } else {
  327. this.home_image = "../../static/home/avator.png";
  328. }
  329. // 如果是音频类型,设置音频源
  330. if (this.queueDetail.task_type == 2 && this.queueDetail.result_audio) {
  331. this.audioPlayer.src = this.queueDetail.result_audio;
  332. }
  333. } else {
  334. uni.showToast({
  335. title: '获取详情失败',
  336. icon: 'none'
  337. });
  338. }
  339. },
  340. complete: () => {
  341. uni.hideLoading();
  342. },
  343. fail: (e) => {
  344. console.log("请求失败:", e);
  345. uni.showToast({
  346. title: '网络请求失败',
  347. icon: 'none'
  348. });
  349. }
  350. });
  351. },
  352. showActionSheet() {
  353. // 显示操作列表
  354. uni.showActionSheet({
  355. itemList: ['修改封面', '删除作品'],
  356. success: (res) => {
  357. switch (res.tapIndex) {
  358. case 0:
  359. // 修改封面
  360. this.editCover();
  361. break;
  362. case 1:
  363. // 删除作品
  364. this.deleteWork();
  365. break;
  366. }
  367. },
  368. fail: (res) => {
  369. console.log(res.errMsg);
  370. }
  371. });
  372. },
  373. // 修改封面
  374. editCover() {
  375. var _self = this;
  376. uni.chooseImage({
  377. count: 1,
  378. sizeType: ['compressed'],
  379. sourceType: ['album', 'camera'],
  380. success: function(res) {
  381. console.log('res:', res)
  382. if (res.tempFilePaths.length > 0) {
  383. _self.imglocal = res.tempFilePaths[0]
  384. const tempFilePaths = res.tempFilePaths[0];
  385. console.log('tempFilePaths:', tempFilePaths);
  386. const uploadTask = uni.uploadFile({
  387. url: _self.$apiHost + '/Xweb/upload_img?skey=' + _self.skey,
  388. filePath: res.tempFilePaths[0],
  389. name: 'file',
  390. success: function(uploadFileRes) {
  391. let resdata = JSON.parse(uploadFileRes.data)
  392. console.log('Success11:', uploadFileRes);
  393. console.log('Success21:', resdata);
  394. if (resdata.success == 'yes') {
  395. _self.home_image = resdata.url;
  396. // 调用修改封面接口
  397. uni.request({
  398. url: _self.$apiHost + '/WorkAI/queueAction',
  399. method: 'GET',
  400. data: {
  401. uuid: getApp().globalData.uuid,
  402. act: 'editImg',
  403. result_images: resdata.url,
  404. id: _self.arcID
  405. },
  406. header: {
  407. 'content-type': 'application/json',
  408. 'sign': getApp().globalData.headerSign
  409. },
  410. success: (res) => {
  411. if (res.data.success === "yes") {
  412. uni.showToast({
  413. title: '修改封面成功',
  414. icon: 'success'
  415. });
  416. } else {
  417. uni.showToast({
  418. title: '修改封面失败',
  419. icon: 'none'
  420. });
  421. }
  422. },
  423. fail: () => {
  424. uni.showToast({
  425. title: '修改封面失败',
  426. icon: 'none'
  427. });
  428. }
  429. });
  430. }
  431. },
  432. fail: function(uploadFileFail) {
  433. console.log('Error:', uploadFileFail.data);
  434. uni.showToast({
  435. title: '图片上传失败',
  436. icon: 'none'
  437. });
  438. }
  439. });
  440. }
  441. },
  442. error: function(e) {
  443. console.log(e);
  444. uni.showToast({
  445. title: '选择图片失败',
  446. icon: 'none'
  447. });
  448. }
  449. });
  450. },
  451. // 删除作品
  452. deleteWork() {
  453. // 显示确认对话框
  454. uni.showModal({
  455. title: '确认删除',
  456. content: '确定要删除这个作品吗?',
  457. confirmColor: '#ff5151',
  458. success: (res) => {
  459. if (res.confirm) {
  460. // 用户点击确定,执行删除操作
  461. this.confirmDelete();
  462. }
  463. }
  464. });
  465. },
  466. // 确认删除
  467. confirmDelete() {
  468. uni.showLoading({
  469. title: '删除中...'
  470. });
  471. uni.request({
  472. url: this.$apiHost + '/WorkAI/queueAction',
  473. method: 'GET',
  474. data: {
  475. uuid: getApp().globalData.uuid,
  476. act: 'del',
  477. id: this.arcID
  478. },
  479. header: {
  480. 'content-type': 'application/json',
  481. 'sign': getApp().globalData.headerSign
  482. },
  483. success: (res) => {
  484. uni.hideLoading();
  485. if (res.data.success === "yes") {
  486. uni.showToast({
  487. title: '删除成功',
  488. icon: 'success'
  489. });
  490. // 删除成功后返回上一页
  491. setTimeout(() => {
  492. uni.navigateBack({
  493. delta: 1
  494. });
  495. }, 1500);
  496. } else {
  497. uni.showToast({
  498. title: '删除失败',
  499. icon: 'none'
  500. });
  501. }
  502. },
  503. fail: () => {
  504. uni.hideLoading();
  505. uni.showToast({
  506. title: '删除失败',
  507. icon: 'none'
  508. });
  509. }
  510. });
  511. },
  512. // 显示添加说明弹窗
  513. showAddNotePopup() {
  514. this.showNotePopup = true;
  515. },
  516. // 关闭添加说明弹窗
  517. closeAddNotePopup() {
  518. this.showNotePopup = false;
  519. },
  520. // 确认添加说明
  521. confirmAddNote() {
  522. if (!this.noteContent.trim()) {
  523. uni.showToast({
  524. title: '请输入说明内容',
  525. icon: 'none'
  526. });
  527. return;
  528. }
  529. uni.showLoading({
  530. title: '保存中...'
  531. });
  532. uni.request({
  533. url: this.$apiHost + '/WorkAI/queueAction',
  534. method: 'GET',
  535. data: {
  536. uuid: getApp().globalData.uuid,
  537. act: 'editContent',
  538. content: this.noteContent,
  539. id: this.arcID
  540. },
  541. header: {
  542. 'content-type': 'application/json',
  543. 'sign': getApp().globalData.headerSign
  544. },
  545. success: (res) => {
  546. uni.hideLoading();
  547. if (res.data.success === "yes") {
  548. uni.showToast({
  549. title: '添加说明成功',
  550. icon: 'success'
  551. });
  552. this.showNotePopup = false;
  553. // this.noteContent = '';
  554. // 重新加载数据
  555. this.loadData();
  556. } else {
  557. uni.showToast({
  558. title: '添加说明失败',
  559. icon: 'none'
  560. });
  561. }
  562. },
  563. fail: () => {
  564. uni.hideLoading();
  565. uni.showToast({
  566. title: '添加说明失败',
  567. icon: 'none'
  568. });
  569. }
  570. });
  571. },
  572. // 发布作品
  573. publishWork() {
  574. uni.showLoading({
  575. title: '发布中...'
  576. });
  577. uni.request({
  578. url: this.$apiHost + '/WorkAI/queueAction',
  579. method: 'GET',
  580. data: {
  581. uuid: getApp().globalData.uuid,
  582. act: 'fabu',
  583. id: this.arcID
  584. },
  585. header: {
  586. 'content-type': 'application/json',
  587. 'sign': getApp().globalData.headerSign
  588. },
  589. success: (res) => {
  590. console.log("resddd", res.data);
  591. uni.hideLoading();
  592. if (res.data.success === "yes") {
  593. uni.showToast({
  594. title: '发布成功',
  595. icon: 'success'
  596. });
  597. // 重新加载数据
  598. // this.loadData();
  599. } else {
  600. uni.showToast({
  601. title: res.data.str || '发布失败',
  602. icon: 'none'
  603. });
  604. }
  605. },
  606. fail: () => {
  607. uni.hideLoading();
  608. uni.showToast({
  609. title: '发布失败',
  610. icon: 'none'
  611. });
  612. }
  613. });
  614. },
  615. startDrag(event) {
  616. this.isDragging = true;
  617. this.startY = event.clientY;
  618. this.initialOffsetY = this.offsetY || 0;
  619. },
  620. stopDrag() {
  621. this.isDragging = false;
  622. },
  623. drag(event) {
  624. if (this.isDragging) {
  625. const deltaY = event.clientY - this.startY;
  626. const newOffsetY = this.initialOffsetY + deltaY;
  627. // Get the height of the lyrics text
  628. const lyricsTextHeight = this.$refs.lyricsText ? this.$refs.lyricsText.clientHeight : 0;
  629. // Define the threshold limits based on the height of the lyrics text
  630. const minY = -lyricsTextHeight + 20; // Allow some space above
  631. const maxY = 20; // Allow some space below
  632. // Apply the limits
  633. this.offsetY = Math.min(Math.max(newOffsetY, minY), maxY);
  634. // Log the height and current offset
  635. console.log('Lyrics Text Height:', lyricsTextHeight);
  636. console.log('Current Offset Y:', this.offsetY);
  637. }
  638. }
  639. }
  640. }
  641. </script>
  642. <style scoped lang="scss">
  643. @import 'makeDetail.scss';
  644. </style>