邃芒慧影、口播(PC) https://neuver.metavatar.cc/
No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.
 
 
 
 

699 líneas
18 KiB

  1. <template>
  2. <div class="page">
  3. <!-- 搜索框 -->
  4. <div class="top">
  5. <div class="flex justify-between" style="width: 300px">
  6. <el-input
  7. v-model="title"
  8. :placeholder="$t('myCreating.search')"
  9. @keyup.enter="searchVideoList"
  10. />
  11. <el-icon class="icon-edit" @click="searchVideoList"
  12. ><i-ep-search
  13. /></el-icon>
  14. </div>
  15. </div>
  16. <!-- 作品列表 -->
  17. <div v-if="!isLoading">
  18. <div v-if="videoList.length > 0" class="workList flex">
  19. <div class="workItem" v-for="item in videoList" :key="item.id">
  20. <div class="workImg">
  21. <img
  22. v-if="item.coverImg"
  23. class="coverImg inmiddle"
  24. :src="item.coverImg"
  25. alt=""
  26. />
  27. <img
  28. v-else
  29. class="takePlace inmiddle"
  30. src="@/assets/img/left-top-logo.png"
  31. alt=""
  32. />
  33. </div>
  34. <div :class="'statusName ' + item.statusName">
  35. {{ $t("myCreating." + item.statusName) }}
  36. </div>
  37. <div class="workInfo flex">
  38. <span>{{ item.title }}</span>
  39. <span>{{ dayjs(item.createDate).format("YYYY-MM-DD") }}</span>
  40. </div>
  41. <!-- 更多遮罩层 -->
  42. <div
  43. class="more"
  44. @mouseleave="mouseleave"
  45. @click="clickVideoItem(item)"
  46. >
  47. <el-icon
  48. v-if="[0].includes(item.videoStatus)"
  49. class="icon-videoPlay"
  50. ><i-ep-edit
  51. /></el-icon>
  52. <el-icon
  53. v-if="[1, 2, 4, 6].includes(item.videoStatus)"
  54. class="icon-videoPlay"
  55. ><i-ep-loading
  56. /></el-icon>
  57. <el-icon
  58. v-if="[3].includes(item.videoStatus)"
  59. class="icon-videoPlay"
  60. ><i-ep-closeBold
  61. /></el-icon>
  62. <el-icon
  63. v-if="[5].includes(item.videoStatus)"
  64. class="icon-videoPlay"
  65. ><i-ep-videoPlay
  66. /></el-icon>
  67. <div class="showBtn" @click.stop="mouseenter(item)">...</div>
  68. <div class="btns" v-show="showPopup">
  69. <!-- 下载按钮 -->
  70. <div
  71. class="btns-item"
  72. @click.stop="handleDownload(item.videoPlayUrl)"
  73. >
  74. <div class="btns-item-icon">
  75. <el-icon class="icon-delete"><i-ep-download /></el-icon>
  76. </div>
  77. <div class="text">{{ $t("myCreating.download") }}</div>
  78. </div>
  79. <!-- 删除按钮 -->
  80. <div
  81. class="btns-item"
  82. @click.stop="handelDelete(item.id, item.title)"
  83. >
  84. <div class="btns-item-icon">
  85. <el-icon class="icon-delete"><i-ep-delete /></el-icon>
  86. </div>
  87. <div class="text">{{ $t("myCreating.delete") }}</div>
  88. </div>
  89. </div>
  90. </div>
  91. </div>
  92. </div>
  93. <div v-if="videoList.length == 0" class="noList">
  94. <div class="title">
  95. {{ $t("myCreating.noList") }}
  96. </div>
  97. <div class="goCreate" @click="goCreate">
  98. {{ $t("myCreating.goCreate") }}
  99. </div>
  100. </div>
  101. </div>
  102. <div v-if="isLoading" class="loadingIcon">
  103. <el-icon class="is-loading">
  104. <svg
  105. viewBox="0 0 1024 1024"
  106. xmlns="http://www.w3.org/2000/svg"
  107. data-v-ea893728=""
  108. >
  109. <path
  110. fill="currentColor"
  111. d="M512 64a32 32 0 0 1 32 32v192a32 32 0 0 1-64 0V96a32 32 0 0 1 32-32zm0 640a32 32 0 0 1 32 32v192a32 32 0 1 1-64 0V736a32 32 0 0 1 32-32zm448-192a32 32 0 0 1-32 32H736a32 32 0 1 1 0-64h192a32 32 0 0 1 32 32zm-640 0a32 32 0 0 1-32 32H96a32 32 0 0 1 0-64h192a32 32 0 0 1 32 32zM195.2 195.2a32 32 0 0 1 45.248 0L376.32 331.008a32 32 0 0 1-45.248 45.248L195.2 240.448a32 32 0 0 1 0-45.248zm452.544 452.544a32 32 0 0 1 45.248 0L828.8 783.552a32 32 0 0 1-45.248 45.248L647.744 692.992a32 32 0 0 1 0-45.248zM828.8 195.264a32 32 0 0 1 0 45.184L692.992 376.32a32 32 0 0 1-45.248-45.248l135.808-135.808a32 32 0 0 1 45.248 0zm-452.544 452.48a32 32 0 0 1 0 45.248L240.448 828.8a32 32 0 0 1-45.248-45.248l135.808-135.808a32 32 0 0 1 45.248 0z"
  112. ></path>
  113. </svg>
  114. </el-icon>
  115. <span class="loadingText">{{ $t("myCreating.loading") }}</span>
  116. </div>
  117. <!-- 弹出框预览作品 -->
  118. <el-dialog
  119. destroy-on-close
  120. class="elDialog"
  121. v-model="showDialog"
  122. :title="presentItem.title"
  123. width="40%"
  124. center
  125. >
  126. <div class="videoBox">
  127. <video
  128. v-if="presentItem.videoPlayUrl"
  129. controls="true"
  130. class=""
  131. :src="presentItem.videoPlayUrl"
  132. ></video>
  133. <div v-else class="insteadVideo">
  134. {{ $t("myCreating." + presentItem.statusName + "Text") }}
  135. <span v-if="presentItem.videoStatus == 3">{{
  136. presentItem.videoMsg
  137. }}</span>
  138. </div>
  139. <!-- 有视频路径的页脚 -->
  140. <div class="footer" v-if="presentItem.videoPlayUrl">
  141. <span class="dialog-footer">
  142. <!-- dialog下载按钮 -->
  143. <button
  144. class="elBtn"
  145. type="primary"
  146. @click.stop="handleDownload(presentItem.videoPlayUrl)"
  147. >
  148. <el-icon class="icon-delete"><i-ep-download /></el-icon
  149. >{{ $t("myCreating.download") }}
  150. </button>
  151. <!-- dialog删除按钮 -->
  152. <button
  153. class="elBtn"
  154. @click.stop="handelDelete(presentItem.id, presentItem.title)"
  155. >
  156. <el-icon class="icon-delete"><i-ep-delete /></el-icon
  157. >{{ $t("myCreating.delete") }}
  158. </button>
  159. </span>
  160. </div>
  161. <!-- 无视频路径的页脚 -->
  162. <div class="footer" v-if="!presentItem.videoPlayUrl">
  163. <span class="dialog-footer">
  164. <!-- dialog编辑按钮 -->
  165. <button
  166. class="elBtn"
  167. type="primary"
  168. @click.stop="
  169. router.push({
  170. path: '/createVideo',
  171. query: { id: presentItem.id },
  172. })
  173. "
  174. v-if="[0, 3].includes(presentItem.videoStatus)"
  175. >
  176. {{ $t("myCreating.edit") }}
  177. </button>
  178. </span>
  179. </div>
  180. </div>
  181. </el-dialog>
  182. <!-- 分页 -->
  183. <div v-if="!isLoading" class="pagination">
  184. <el-pagination
  185. v-model:current-page="pageNum"
  186. v-model:page-size="pageSize"
  187. :page-sizes="[10, 20, 50, 100, 200]"
  188. :small="false"
  189. :disabled="false"
  190. :background="true"
  191. layout="total, sizes, prev, pager, next, jumper"
  192. :total="total"
  193. @size-change="handleSizeChange"
  194. @current-change="handleCurrentChange"
  195. />
  196. </div>
  197. </div>
  198. </template>
  199. <script setup>
  200. import {
  201. userPhotoVideoListApi,
  202. delUserPhotoVideoByIDApi,
  203. } from "@/apis/myCreating";
  204. import { timestampToTime } from "@/utils/tools";
  205. import { useI18n } from "vue-i18n";
  206. import { getStatus } from "./videoStatus";
  207. import { useRouter } from "vue-router";
  208. import dayjs from "dayjs";
  209. const router = useRouter();
  210. // 当前语言状态与国际化组件
  211. const { locale } = useI18n();
  212. const lanChange = ref(locale);
  213. const title = ref("");
  214. const pageNum = ref(1);
  215. const pageSize = ref(10);
  216. const total = ref(0);
  217. // 弹窗显示隐藏
  218. const showDialog = ref(false);
  219. const isLoading = ref(true);
  220. // 当前作品
  221. const presentItem = ref("");
  222. // 作品列表
  223. const videoList = ref([]);
  224. const handleSizeChange = (val) => {
  225. pageSize.value = val;
  226. getPhotoVideoList(pageNum.value, pageSize.value, title.value);
  227. };
  228. const handleCurrentChange = (val) => {
  229. pageNum.value = val;
  230. getPhotoVideoList(pageNum.value, pageSize.value, title.value);
  231. };
  232. // 点击作品
  233. function clickVideoItem(item) {
  234. showDialog.value = true;
  235. presentItem.value = item;
  236. }
  237. // 删除框是否显示
  238. let showPopup = ref(false);
  239. function mouseleave() {
  240. showPopup.value = false;
  241. }
  242. function mouseenter(item) {
  243. presentItem.value = item;
  244. showPopup.value = !showPopup.value;
  245. }
  246. // 下载
  247. function handleDownload(itemVideoPlayUrl) {
  248. if (itemVideoPlayUrl) {
  249. const link = document.createElement("a");
  250. link.href = itemVideoPlayUrl;
  251. document.body.appendChild(link);
  252. link.click();
  253. document.body.removeChild(link);
  254. } else {
  255. ElMessage.error(
  256. lanChange.value == "zh-cn" ? `无法下载` : `Unable to download`
  257. );
  258. }
  259. }
  260. function goCreate() {
  261. router.push("/createVideo");
  262. }
  263. function searchVideoList() {
  264. getPhotoVideoList(pageNum.value, pageSize.value, title.value, true);
  265. }
  266. function handelDelete(id, title) {
  267. const msg =
  268. lanChange.value == "zh-cn"
  269. ? `确定要删除这个作品吗? 作品标题:${title}`
  270. : `Are you sure to delete this video ? Title:${title};`;
  271. const notice = lanChange.value == "zh-cn" ? "提示" : "Notice";
  272. const confirm = lanChange.value == "zh-cn" ? "确定" : "Confirm";
  273. const cancel = lanChange.value == "zh-cn" ? "取消" : "Cancel";
  274. ElMessageBox.confirm(msg, notice, {
  275. confirmButtonText: confirm,
  276. cancelButtonText: cancel,
  277. }).then(() => {
  278. delPhotoVideo(id);
  279. });
  280. }
  281. /**
  282. * @description:获取我的视频作品
  283. * @return: data
  284. */
  285. function getPhotoVideoList(pageNum, pageSize, title, searchFlag) {
  286. userPhotoVideoList(pageNum, pageSize, title)
  287. .then((res) => {
  288. console.log(res, "res");
  289. res.data.list.forEach((item) => {
  290. // item.createDate = timestampToTime(item.createDate) || "";
  291. // item.updateDate = timestampToTime(item.updateDate) || "";
  292. // item.createVideoDate = timestampToTime(item.createVideoDate) || "";
  293. item.statusName = getStatus(item.videoStatus);
  294. });
  295. videoList.value = res.data.list;
  296. total.value = res.data.total * 1;
  297. if (searchFlag) {
  298. const total = res.data.total;
  299. const msg1 =
  300. lanChange.value == "zh-cn"
  301. ? `查询成功!找到${total}条符合条件的视频`
  302. : `Found! Match ${total} videos`;
  303. const msg2 =
  304. lanChange.value == "zh-cn"
  305. ? `查询成功!没有符合条件的视频`
  306. : `Found! No match videos`;
  307. const msg3 =
  308. lanChange.value == "zh-cn"
  309. ? `查询成功!已加载全部视频`
  310. : `Found! Present all videos`;
  311. return title
  312. ? ElMessage.success(total > 0 ? msg1 : msg2)
  313. : ElMessage.success(msg3);
  314. }
  315. isLoading.value = false;
  316. })
  317. .catch((err) => {
  318. console.log(err, "err");
  319. });
  320. }
  321. /**
  322. * @description:删除视频作品
  323. * @param: videoID
  324. * @return: data
  325. */
  326. function delPhotoVideo(videoID) {
  327. delUserPhotoVideoByID(videoID)
  328. .then((res) => {
  329. console.log(res, "res");
  330. const msg = lanChange.value == "zh-cn" ? `删除成功!` : `Success !`;
  331. ElMessage.success(msg);
  332. showDialog.value = false;
  333. getPhotoVideoList(pageNum.value, pageSize.value, title.value);
  334. })
  335. .catch((err) => {
  336. console.log(err, "err");
  337. ElMessage.error(err.message);
  338. });
  339. }
  340. onMounted(() => {
  341. isLoading.value = true;
  342. getPhotoVideoList(pageNum.value, pageSize.value, title.value);
  343. });
  344. </script>
  345. <style lang="scss" scoped>
  346. .page {
  347. min-height: calc(100vh - 80px);
  348. padding: 15px 130px;
  349. background-color: #fff;
  350. border-radius: 25px 0 0;
  351. .top {
  352. margin-bottom: 35px;
  353. }
  354. .loadingIcon {
  355. height: 100px;
  356. line-height: 100px;
  357. text-align: center;
  358. transform: scale(2);
  359. .loadingText {
  360. position: relative;
  361. top: -2px;
  362. left: 4px;
  363. }
  364. }
  365. .workList {
  366. flex-wrap: wrap;
  367. justify-content: flex-start;
  368. width: 100%;
  369. // height: 200px;
  370. margin-top: 5px;
  371. padding-bottom: 50px;
  372. cursor: pointer;
  373. .workItem {
  374. position: relative;
  375. width: 300px;
  376. // height: 200px;
  377. margin: 0 20px 20px 0;
  378. border: 2px solid #c2c2c2;
  379. border-radius: 15px;
  380. cursor: pointer;
  381. overflow: hidden;
  382. .workImg {
  383. position: relative;
  384. width: 100%;
  385. height: 170px;
  386. cursor: pointer;
  387. padding: 10px;
  388. overflow: hidden;
  389. .coverImg {
  390. max-width: 90%;
  391. max-height: 170px;
  392. cursor: pointer;
  393. }
  394. .takePlace {
  395. position: absolute;
  396. top: 40%;
  397. width: 80%;
  398. }
  399. }
  400. .more {
  401. position: absolute;
  402. top: 0;
  403. left: 0;
  404. width: 100%;
  405. height: 170px;
  406. background-color: rgb(0 0 0 / 30%);
  407. cursor: pointer;
  408. opacity: 0;
  409. transition: all 0.2s;
  410. .icon-videoPlay {
  411. position: absolute;
  412. top: 50%;
  413. left: 50%;
  414. width: 50px;
  415. height: 50px;
  416. font-size: 50px;
  417. color: #fff;
  418. text-align: center;
  419. transform: translate(-50%, -50%);
  420. cursor: pointer;
  421. }
  422. .showBtn {
  423. position: absolute;
  424. top: 10px;
  425. right: 10px;
  426. width: 20px;
  427. height: 20px;
  428. font-size: 20px;
  429. line-height: 10px;
  430. color: #fff;
  431. text-align: center;
  432. transition: all 0.3s;
  433. cursor: pointer;
  434. border-radius: 2px;
  435. &:hover {
  436. background-color: #00000056;
  437. }
  438. }
  439. .btns {
  440. position: absolute;
  441. top: 45px;
  442. right: 10px;
  443. // width: 70px;
  444. // height: 60px;
  445. overflow: hidden;
  446. border-radius: 10px;
  447. cursor: pointer;
  448. &-item {
  449. // width: 70px;
  450. // height: 30px;
  451. text-align: center;
  452. background-color: #fff;
  453. padding: 0 10px;
  454. transition: all 0.3s;
  455. cursor: pointer;
  456. &-icon {
  457. position: relative;
  458. display: inline-block;
  459. width: 20px;
  460. height: 20px;
  461. cursor: pointer;
  462. .icon-delete {
  463. position: absolute;
  464. top: 4px;
  465. left: 0;
  466. width: 20px;
  467. height: 20px;
  468. font-size: 16px;
  469. color: #000;
  470. text-align: center;
  471. cursor: pointer;
  472. }
  473. }
  474. .text {
  475. display: inline-block;
  476. height: 30px;
  477. padding-left: 5px;
  478. margin-top: -5px;
  479. line-height: 20px;
  480. cursor: pointer;
  481. }
  482. &:hover {
  483. color: #ffffff;
  484. background-color: #0000001a;
  485. }
  486. }
  487. }
  488. }
  489. .workInfo {
  490. justify-content: space-between;
  491. height: 40px;
  492. padding: 0 10px;
  493. line-height: 40px;
  494. border-top: 1px solid #afafaf;
  495. white-space: nowrap;
  496. overflow: hidden;
  497. text-overflow: ellipsis;
  498. font-size: 13px;
  499. }
  500. .statusName {
  501. position: absolute;
  502. top: 10%;
  503. left: -10%;
  504. width: 120px;
  505. text-align: center;
  506. color: #ffffff;
  507. font-size: 14px;
  508. transform: rotate(-45deg);
  509. &.manuscript {
  510. /* 草稿 */
  511. background: linear-gradient(to right, #d7d2cc 0%, #304352 100%);
  512. }
  513. &.generating {
  514. /* 生成中 */
  515. background: linear-gradient(270deg, #4b61dc, #15d1b8);
  516. }
  517. &.generationFailed {
  518. /* 生成失败 */
  519. background: linear-gradient(120deg, #f093fb 0%, #f5576c 100%);
  520. }
  521. &.generationSucceed {
  522. /* 生成成功 */
  523. background: linear-gradient(120deg, #84fab0 0%, #8fd3f4 100%);
  524. }
  525. }
  526. &:hover {
  527. .more {
  528. opacity: 1;
  529. }
  530. }
  531. }
  532. }
  533. .noList {
  534. .title {
  535. font-size: 30px;
  536. text-align: center;
  537. margin-top: 100px;
  538. background-image: -webkit-linear-gradient(
  539. left,
  540. #4b61dc,
  541. #15d1b8 25%,
  542. #4b61dc 50%,
  543. #15d1b8 75%,
  544. #4b61dc
  545. ) !important;
  546. -webkit-text-fill-color: transparent !important;
  547. -webkit-background-clip: text !important;
  548. background-clip: text !important;
  549. -webkit-background-size: 200% 100% !important;
  550. background-size: 200% 100% !important;
  551. }
  552. .goCreate {
  553. width: 200px;
  554. height: 40px;
  555. line-height: 40px;
  556. text-align: center;
  557. color: #ffffff;
  558. border-radius: 6px;
  559. background: linear-gradient(270deg, #4b61dc, #15d1b8);
  560. margin: 30px auto;
  561. cursor: pointer;
  562. transition: all 0.3s;
  563. &:hover {
  564. transform: scale(1.1);
  565. }
  566. }
  567. }
  568. .pagination {
  569. position: fixed;
  570. bottom: 20px;
  571. left: 50%;
  572. transform: translateX(-50%);
  573. background-color: #ffffff;
  574. padding: 10px 20px;
  575. border-radius: 8px;
  576. transition: all 0.3s;
  577. cursor: pointer;
  578. &:hover {
  579. background-color: #b8b8b873;
  580. }
  581. }
  582. }
  583. :deep(.el-input__wrapper) {
  584. border: none;
  585. border-bottom: 2px solid #000;
  586. border-radius: 0;
  587. box-shadow: none;
  588. }
  589. .el-icon.icon-edit {
  590. width: 30px;
  591. height: 30px;
  592. font-size: 30px;
  593. color: #8c939d;
  594. text-align: center;
  595. cursor: pointer;
  596. transition: all 0.3s;
  597. &:hover {
  598. color: #292929;
  599. }
  600. }
  601. .elDialog {
  602. .videoBox {
  603. // display: flex;
  604. // justify-content: space-between;
  605. width: 100%;
  606. padding: 20px;
  607. video {
  608. width: 100%;
  609. max-height: 600px;
  610. margin: auto;
  611. }
  612. .insteadVideo {
  613. font-size: 20px;
  614. font-weight: 600;
  615. margin: 20px auto;
  616. text-align: center;
  617. }
  618. }
  619. .dialog-footer {
  620. display: flex;
  621. justify-content: space-between;
  622. .elBtn {
  623. color: #fff;
  624. border-radius: 10px;
  625. padding: 5px 10px;
  626. cursor: pointer;
  627. background-color: #000;
  628. transition: all 0.3s;
  629. &:hover {
  630. background-color: #15d1b8;
  631. }
  632. }
  633. :deep(.el-icon) {
  634. margin-right: 5px;
  635. font-weight: 700;
  636. }
  637. }
  638. }
  639. :deep(.el-dialog) {
  640. overflow: hidden;
  641. border-radius: 25px;
  642. }
  643. // :deep(.el-dialog__header) {
  644. // }
  645. :deep(.el-dialog__title) {
  646. background-image: -webkit-linear-gradient(
  647. left,
  648. #4b61dc,
  649. #15d1b8 25%,
  650. #4b61dc 50%,
  651. #15d1b8 75%,
  652. #4b61dc
  653. ) !important;
  654. -webkit-text-fill-color: transparent !important;
  655. -webkit-background-clip: text !important;
  656. background-clip: text !important;
  657. -webkit-background-size: 200% 100% !important;
  658. background-size: 200% 100% !important;
  659. }
  660. :deep(.el-dialog__body) {
  661. padding: 0;
  662. }
  663. :deep(.dialog__footer) {
  664. padding: 0;
  665. }
  666. </style>