Ver código fonte

视频生成

release
HolyKnightIX 2 anos atrás
pai
commit
c42b9199c9
14 arquivos alterados com 695 adições e 57 exclusões
  1. BIN
      src/assets/img/BG@2x.png
  2. BIN
      src/assets/img/loading.png
  3. BIN
      src/assets/img/play.png
  4. +1
    -0
      src/components/home/home.vue
  5. +2
    -0
      src/main.js
  6. +12
    -8
      src/router/index.js
  7. +47
    -0
      src/utils/timestampToTime.js
  8. +1
    -0
      src/views/model/chooseModel.vue
  9. +112
    -0
      src/views/model/downloadVideo.vue
  10. +326
    -0
      src/views/model/generateVideo.vue
  11. +77
    -13
      src/views/model/getPaper.vue
  12. +7
    -1
      src/views/model/modelDetail.vue
  13. +1
    -0
      src/views/model/selectSound.vue
  14. +109
    -35
      src/views/myPage/myPage.vue

BIN
src/assets/img/BG@2x.png Ver arquivo

Antes Depois
Largura: 3840  |  Altura: 2160  |  Tamanho: 6.2 MiB

BIN
src/assets/img/loading.png Ver arquivo

Antes Depois
Largura: 200  |  Altura: 200  |  Tamanho: 4.4 KiB

BIN
src/assets/img/play.png Ver arquivo

Antes Depois
Largura: 128  |  Altura: 128  |  Tamanho: 4.3 KiB

+ 1
- 0
src/components/home/home.vue Ver arquivo

@@ -621,6 +621,7 @@ export default {
if (res.data.code == 1052) {
this.$router.push("/login");
Toast.fail("登录过期,请重新登录!");
return;
} else {
this.$router.push("/myPage");
}


+ 2
- 0
src/main.js Ver arquivo

@@ -3,6 +3,7 @@ import App from './App.vue'
import './registerServiceWorker'
import router from './router'
import store from './store'
import Vant from 'vant';
import 'vant/lib/index.css'
// 引入lib-flexible做rem适配
import 'lib-flexible'
@@ -11,6 +12,7 @@ import ElementUI from 'element-ui'; //引入js
import 'element-ui/lib/theme-chalk/index.css';//引入css

Vue.use(ElementUI);
Vue.use(Vant);





+ 12
- 8
src/router/index.js Ver arquivo

@@ -19,57 +19,61 @@ const routes = [
{
path: '/aboutUe',
name: 'aboutUe',
// component: Home
component: () => import("../components/aboutUe/aboutUe"),
},
{
path: '/styleAdd',
name: 'styleAdd',
// component: Home
component: () => import("../components/styleAdd/styleAdd"),
},
// 登录
{
path: '/login',
name: 'login',
// component: Home
component: () => import("../views/login/login"),
},
// 创作中心首页
{
path: '/myPage',
name: 'myPage',
// component: Home
component: () => import("../views/myPage/myPage"),
},
// 选择模板
{
path: '/chooseModel',
name: 'chooseModel',
// component: Home
component: () => import("../views/model/chooseModel"),
},
// 模板详情
{
path: '/modelDetail',
name: 'modelDetail',
// component: Home
component: () => import("../views/model/modelDetail"),
},
// 选择语音
{
path: '/selectSound',
name: 'selectSound',
// component: Home
component: () => import("../views/model/selectSound"),
},
// 录入文案
{
path: '/getPaper',
name: 'getPaper',
// component: Home
component: () => import("../views/model/getPaper"),
},
// 合成视频
{
path: '/generateVideo',
name: 'generateVideo',
component: () => import("../views/model/generateVideo"),
},
// 下载视频
{
path: '/downloadVideo',
name: 'downloadVideo',
component: () => import("../views/model/downloadVideo"),
},
]

const router = new VueRouter({


+ 47
- 0
src/utils/timestampToTime.js Ver arquivo

@@ -0,0 +1,47 @@
/**
* @description 根据时间戳获取时间
* @param {*} timestamp 必传,number类型,时间戳数据(10位及以下,10位至13位)
* @param {*} format 选传,string类型,提供以下时间格式:YYYY-MM-DD hh:mm:ss、YYYY/MM/DD hh:mm:ss、YYYY.MM.DD hh:mm:ss、YYYY MM DD hh:mm:ss、YYYY年MM月DD日 hh:mm:ss、YYYY-MM-DD、YYYY/MM/DD、YYYY.MM.DD、YYYY MM DD、YYYY年MM月DD日;若不传,则默认为:YYYY-MM-DD
* @returns 根据要求的时间格式
* @version V 1.0, Created by YWQ, 2022.10.20
*/
const timestampToTime = (timestamp, format) => {
//时间戳为10位需*1000,时间戳为13位不需乘1000
const length = timestamp.length
if (length <= 10) {
var date = new Date(timestamp * 1000)
} else {
var date = new Date(timestamp)
}
let Y = String(date.getFullYear())
let M = String(date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1)
let D = String(date.getDate() + 1 < 10 ? '0' + (date.getDate()) : date.getDate())
let h = String(date.getHours() + 1 < 10 ? '0' + (date.getHours()) : date.getHours())
let m = String(date.getMinutes() + 1 < 10 ? '0' + (date.getMinutes()) : date.getMinutes())
let s = String(date.getSeconds() + 1 < 10 ? '0' + (date.getSeconds()) : date.getSeconds())
// return Y + M + D + h + m + s
if (format == "YYYY-MM-DD hh:mm:ss") {
return Y + "-" + M + "-" + D + " " + h + ":" + m + ":" + s
} else if (format == "YYYY/MM/DD hh:mm:ss") {
return Y + "/" + M + "/" + D + " " + h + ":" + m + ":" + s
} else if (format == "YYYY.MM.DD hh:mm:ss") {
return Y + "." + M + "." + D + " " + h + ":" + m + ":" + s
} else if (format == "YYYY MM DD hh:mm:ss") {
return Y + " " + M + " " + D + " " + h + ":" + m + ":" + s
} else if (format == "YYYY年MM月DD日 hh:mm:ss") {
return Y + "年" + M + "月" + D + "日" + " " + h + ":" + m + ":" + s
} else if (format == "YYYY-MM-DD") {
return Y + "-" + M + "-" + D
} else if (format == "YYYY/MM/DD") {
return Y + "/" + M + "/" + D
} else if (format == "YYYY.MM.DD") {
return Y + "." + M + "." + D
} else if (format == "YYYY MM DD") {
return Y + " " + M + " " + D
} else if (format == "YYYY年MM月DD日") {
return Y + "年" + M + "月" + D + "日"
} else {
return Y + "-" + M + "-" + D
}
}
export default timestampToTime

+ 1
- 0
src/views/model/chooseModel.vue Ver arquivo

@@ -94,6 +94,7 @@ export default {
if (res.data.code == 1052) {
this.$router.push("/login");
Toast.fail("登录过期,请重新登录!");
return;
}
this.modeList = res.data.data.list;
})


+ 112
- 0
src/views/model/downloadVideo.vue Ver arquivo

@@ -0,0 +1,112 @@
<template>
<div>
<HeadTop />
<div class="video">
<video :src="videoDetail.videoPathUri + videoDetail.videoPath" />
<div class="desc">
视频已保存到 <span @click="go('/myPage')">我的视频作品</span>
</div>
<img src="../../assets/img/play.png" @click="play" />
</div>
<div class="bottomBtn">
<div class="back" @click="backToIndex">返回首页</div>
<div class="next" @click="play">下载视频</div>
</div>
</div>
</template>

<script>
import Vue from "vue";
import { Toast } from "vant";
import baseUrl from "../../api/baseUrl";
import { mapState, mapActions } from "vuex";
import HeadTop from "./../../components/common/head.vue";

Vue.use(Toast);
export default {
components: {
HeadTop,
},
data() {
return {
videoDetail: {},
};
},
computed: {
...mapState({
characters: (state) => state.publicObj.characters,
}),
},

methods: {
...mapActions(["setCharacters"]),

go(url) {
this.$router.push(url);
},
backToIndex() {
this.$router.push("/myPage");
},
play() {
location.href =
this.videoDetail.videoPathUri + this.videoDetail.videoPath;
},

download() {},
},
created() {
this.videoDetail = this.$route.query.videoDetail;
console.log(this.videoDetail);
},
};
</script>

<style lang="scss" scoped>
.video {
position: relative;
padding: 30px;
text-align: center;
.title {
font-size: 18px;
margin-bottom: 20px;
}
video {
width: 80%;
}
img {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.desc {
font-size: 16px;
margin-top: 20px;
span {
color: #00ccff;
text-decoration: underline;
}
}
}
.bottomBtn {
display: flex;
justify-content: space-between;
padding: 0 75px;
margin-top: 20px;
margin-bottom: 20px;
div {
width: 100px;
height: 30px;
color: #484848;
line-height: 30px;
text-align: center;
border: 1px solid #484848;
border-radius: 7px;
&.next {
color: #fff;
border: 1px solid #00ccff;
background-color: #00ccff;
}
}
}
</style>

+ 326
- 0
src/views/model/generateVideo.vue Ver arquivo

@@ -0,0 +1,326 @@
<template>
<div>
<HeadTop />
<div class="chooseModel">
<div class="active">选择模板</div>
<div class="active">录入文案</div>
<div class="active">合成视频</div>
</div>
<div class="coverImg">
<img :src="coverImg" />
</div>
<div class="backGround">
<div class="select">请选择视频背景</div>
<div class="backGroundList">
<div
@click="setIn(1)"
:class="setIndex == 1 ? 'active' : ''"
style="background-color: red"
></div>
<div
@click="setIn(2)"
:class="setIndex == 2 ? 'active' : ''"
style="background-color: orange"
></div>
<div
@click="setIn(3)"
:class="setIndex == 3 ? 'active' : ''"
style="background-color: yellow"
></div>
<div
@click="setIn(4)"
:class="setIndex == 4 ? 'active' : ''"
style="background-color: green"
></div>
<div
@click="setIn(5)"
:class="setIndex == 5 ? 'active' : ''"
style="background-color: aqua"
></div>
<div
@click="setIn(6)"
:class="setIndex == 6 ? 'active' : ''"
style="background-color: blue"
></div>
<div
@click="setIn(7)"
:class="setIndex == 7 ? 'active' : ''"
style="background-color: purple"
></div>
</div>
<div>合成视频剩余时长:3:00</div>
</div>
<div class="bottomBtn">
<div class="back" @click="back">上一步</div>
<div class="next" @click="submit">合成视频</div>
</div>
<div :class="isShowCover ? 'coverUp active' : 'coverUp'">
<div class="inside" @click="goMy">
<img src="../../assets/img/loading.png" alt="" />
<div class="text">视频合成中,请稍等</div>
</div>
</div>
</div>
</template>

<script>
import Vue from "vue";
import { Toast } from "vant";
import baseUrl from "../../api/baseUrl";
import { mapState, mapActions } from "vuex";
import HeadTop from "./../../components/common/head.vue";

Vue.use(Toast);
export default {
components: {
HeadTop,
},
data() {
return {
isShowCover: false,
show: false,
setIndex: 1,
coverImg: "",
id: "",
timerOver: false,
};
},
computed: {
...mapState({
characters: (state) => state.publicObj.characters,
}),
},

methods: {
...mapActions(["setCharacters"]),

go(url) {
this.$router.push(url);
},

setIn(num) {
this.setIndex = num;
},

back() {
this.$router.back();
},

goMy() {
if (this.isShowCover == true) {
this.$router.push("/myPage");
}
},

findVideo() {
const AccessToken = localStorage.getItem("AccessToken");
const data = {
id: this.id,
};
this.$axios({
method: "get",
url: `${baseUrl}/api/userVideo/findVideo?id=${this.id}`,
headers: {
"Content-Type": "application/json;charset=UTF-8",
token: AccessToken,
},
data,
})
.then((res) => {
if (res.data.code == 1052) {
this.$router.push("/login");
Toast.fail("登录过期,请重新登录!");
return;
}

if (res.data.data.videoStatus == 2) {
this.isShowCover = false;
Toast.success("视频生成成功!");
this.$router.push({
path: "/downloadVideo",
query: {
videoDetail: res.data.data,
},
});
this.timerOver = true;
return;
} else if (res.data.data.videoStatus == 3) {
this.isShowCover = false;
Toast.fail(`视频生成失败!失败原因:${res.data.data.videoMsg}`);
this.timerOver = true;
return;
}
})
.catch((err) => {
Toast.fail(err.message);
});
},

submit() {
const AccessToken = localStorage.getItem("AccessToken");
const data = {
id: this.id,
};
this.$axios({
method: "post",
url: `${baseUrl}/api/userVideo/createVideo`,
headers: {
"Content-Type": "application/json;charset=UTF-8",
token: AccessToken,
},
data,
})
.then((res) => {
if (res.data.code == 1052) {
this.$router.push("/login");
Toast.fail("登录过期,请重新登录!");
return;
}
if (res.data.code != 200) {
Toast.fail(res.data.message);
} else {
Toast.success("提交成功!");
setTimeout(() => {
this.isShowCover = true;
}, 2000);
const timer = setInterval(() => {
this.findVideo();
if (this.timerOver) {
clearInterval(timer);
}
}, 1000);
}
})
.catch((err) => {
Toast.fail(err.message);
});
},
},
created() {
this.coverImg = this.$route.query.coverImg;
this.id = this.$route.query.id;
},
};
</script>

<style lang="scss" scoped>
.chooseModel {
display: flex;
justify-content: space-between;
align-items: center;
width: 350px;
height: 32px;
margin: auto;
margin-top: 15px;
margin-bottom: 15px;
div {
width: 33.33%;
height: 90%;
line-height: 32px;
text-align: center;
border: 1px solid #46464661;
&.active {
background-color: #00ccff;
color: #fff;
}
}
}
.coverImg {
text-align: center;
margin: 25px auto;

img {
width: 270px;
height: 380px;
}
}
.backGround {
padding-left: 10px;
.select {
font-size: 14px;
margin-bottom: 10px;
}
.backGroundList {
display: flex;
overflow-x: auto;

div {
width: 120px;
height: 120px;
margin-right: 10px;
flex-shrink: 0;
&.active {
border: 2px solid #000;
width: 118px;
height: 118px;
transition: all 0.5s;
}
}
// 隐藏滚动条
&::-webkit-scrollbar {
width: 0 !important;
}
}
}
.bottomBtn {
display: flex;
justify-content: space-between;
padding: 0 75px;
margin-top: 20px;
margin-bottom: 20px;
div {
width: 100px;
height: 30px;
color: #484848;
line-height: 30px;
text-align: center;
border: 1px solid #484848;
border-radius: 7px;
&.next {
color: #fff;
border: 1px solid #00ccff;
background-color: #00ccff;
}
}
}

@keyframes rotation {
from {
-webkit-transform: rotate(0deg);
}
to {
-webkit-transform: rotate(360deg);
}
}
.coverUp {
position: fixed;
top: 0;
left: 0;
opacity: 0;
text-align: center;
transition: all 0.3s;
.inside {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);

img {
width: 80px;
height: 80px;
animation: rotation 2s linear infinite;
}
.text {
font-size: 18px;
color: #fff;
}
}
&.active {
width: 100%;
height: 100%;
background-color: #00000077;
z-index: 99999;
opacity: 1;
}
}
</style>

+ 77
- 13
src/views/model/getPaper.vue Ver arquivo

@@ -15,6 +15,7 @@
<div class="voice">语音输入</div>
</div>
<div class="textarea">
<input v-model="title" type="text" placeholder="请输入标题" />
<textarea
v-model="paperwork"
cols="55"
@@ -33,10 +34,10 @@

<script>
import Vue from "vue";
import { mapState, mapActions } from "vuex";
import HeadTop from "./../../components/common/head.vue";
import { Toast } from "vant";
import baseUrl from "../../api/baseUrl";
import { mapState, mapActions } from "vuex";
import HeadTop from "./../../components/common/head.vue";

Vue.use(Toast);
export default {
@@ -46,7 +47,9 @@ export default {
data() {
return {
paperwork: "",
title: "",
modelDetail: {},
id: "",
};
},
computed: {
@@ -65,18 +68,58 @@ export default {
back() {
this.$router.back();
},

getDetailById(id) {
const AccessToken = localStorage.getItem("AccessToken");

this.$axios({
method: "get",
url: `${baseUrl}/api/userVideo/findById?id=${id}`,
headers: {
"Content-Type": "application/json;charset=UTF-8",
token: AccessToken,
},
})
.then((res) => {
if (res.data.code == 1052) {
this.$router.push("/login");
Toast.fail("登录过期,请重新登录!");
return;
}
this.modelDetail = res.data.data.personMould;
})
.catch((err) => {
Toast.fail(err.message);
});
},

goNext() {
const AccessToken = localStorage.getItem("AccessToken");
const data = {
// id: "",
type: 1,
personMouldId: this.modelDetail.id, //模板id
personMouldPath: this.modelDetail.mouldPath, //模板标识
paperwork: this.paperwork,
title: this.modelDetail.title,
// voiceMouldId: "",
// voiceMouldId: "",
};
let data = {};
if (this.id) {
data = {
id: this.id,
type: 1,
personMouldId: this.modelDetail.id, //模板id
personMouldPath: this.modelDetail.mouldPath, //模板标识
paperwork: this.paperwork,
title: this.modelDetail.title,
// voiceMouldId: "",
// voiceMouldId: "",
};
} else {
data = {
// id: "",
type: 1,
personMouldId: this.modelDetail.id, //模板id
personMouldPath: this.modelDetail.mouldPath, //模板标识
paperwork: this.paperwork,
title: this.modelDetail.title,
// voiceMouldId: "",
// voiceMouldId: "",
};
}

this.$axios({
method: "post",
url: `${baseUrl}/api/userVideo/saveOrUpdate`,
@@ -90,7 +133,15 @@ export default {
if (res.data.code == 1052) {
this.$router.push("/login");
Toast.fail("登录过期,请重新登录!");
return;
}
this.$router.push({
path: "/generateVideo",
query: {
coverImg: this.modelDetail.coverImg,
id: res.data.data.id,
},
});
})
.catch((err) => {
Toast.fail(err.message);
@@ -98,7 +149,12 @@ export default {
},
},
created() {
this.modelDetail = this.$route.query.modelDetail;
this.id = this.$route.query.id;
if (this.id) {
this.getDetailById(this.id);
} else {
this.modelDetail = this.$route.query.modelDetail;
}
},
};
</script>
@@ -166,6 +222,11 @@ export default {
position: relative;
text-align: center;
margin-bottom: 60px;
input {
height: 20px;
border: 1px solid #000;
margin-bottom: 15px;
}
textarea {
border: 1px solid #00000080;
}
@@ -207,4 +268,7 @@ export default {
}
}
}
.van-popup {
background-color: #ffffff00 !important;
}
</style>

+ 7
- 1
src/views/model/modelDetail.vue Ver arquivo

@@ -22,7 +22,7 @@
<span class="selectSound" @click="goSelectSound">更换声音</span>
</div>
<div class="bottomBtn">
<div class="set">高级设置</div>
<div class="set" @click="back">上一步</div>
<div class="next" @click="goNext">下一步</div>
</div>
</div>
@@ -60,6 +60,10 @@ export default {
this.$router.push(url);
},

back() {
this.$router.back();
},

getSex(num) {
if (num == 1) {
return "男";
@@ -86,6 +90,7 @@ export default {
if (res.data.code == 1052) {
this.$router.push("/login");
Toast.fail("登录过期,请重新登录!");
return;
}
this.modelDetail = res.data.data;
})
@@ -116,6 +121,7 @@ export default {
if (res.data.code == 1052) {
this.$router.push("/login");
Toast.fail("登录过期,请重新登录!");
return;
}
this.$router.push({
path: "/getPaper",


+ 1
- 0
src/views/model/selectSound.vue Ver arquivo

@@ -81,6 +81,7 @@ export default {
if (res.data.code == 1052) {
this.$router.push("/login");
Toast.fail("登录过期,请重新登录!");
return;
}
this.soundList = res.data.data.list;
})


+ 109
- 35
src/views/myPage/myPage.vue Ver arquivo

@@ -1,47 +1,42 @@
<template>
<div class="page">
<HeadTop />
<img class="showIMG" src="../../assets/img/testIMG.png" alt="" />
<img class="showIMG" src="../../assets/img/BG@2x.png" alt="" />
<div class="item">
<div class="title">我的视频作品</div>
<div class="itemList">
<div class="videoModel">
<div
v-if="videoList.length > 0"
class="videoModel"
v-for="(item, index) in videoList"
:key="index"
@click="goDetail(item)"
>
<div class="videoPrv">
<img src="../../assets/img/imgPrv.png" />
<video :src="item.videoPathUri + item.videoPath" />
</div>
<div class="videoInfo">
<div class="videoName">
视频名称视频名称视频名称视频名称视频名称视频名称
{{ item.title || "暂无" }}
</div>
<div class="createTime">创建时间:2022-10-18 12:13:14</div>
</div>
</div>

<div class="videoModel">
<div class="videoPrv">
<img src="../../assets/img/imgPrv.png" />
</div>
<div class="videoInfo">
<div class="videoName">
视频名称视频名称视频名称视频名称视频名称视频名称
<div class="createTime">
创建时间:{{ changeTime(item.createDate, "YYYY-MM-DD hh:mm:ss") }}
</div>
<div class="createTime">创建时间:2022-10-18 12:13:14</div>
</div>
</div>

<div class="videoModel">
<div class="videoPrv">
<img src="../../assets/img/imgPrv.png" />
</div>
<div class="videoInfo">
<div class="videoName">
视频名称视频名称视频名称视频名称视频名称视频名称
</div>
<div class="createTime">创建时间:2022-10-18 12:13:14</div>
</div>
<div v-if="item.videoStatus == 0" class="tag text">草稿</div>
<div v-if="item.videoStatus == 1" class="tag generating">生成中</div>
<div v-if="item.videoStatus == 2" class="tag finish">已完成</div>
<div v-if="item.videoStatus == 3" class="tag fail">失败</div>
</div>
<div v-if="videoList.length <= 0" class="noWork">暂无作品</div>
</div>
</div>
<van-pagination
v-model="currentPage"
:total-items="total"
:items-per-page="3"
@change="pageChange"
/>
<div class="goAdd" @click="goCreateNew">+ 创作新作品</div>
</div>
</template>
@@ -52,6 +47,7 @@ import HeadTop from "./../../components/common/head.vue";
import { mapState, mapActions } from "vuex";
import { Toast } from "vant";
import baseUrl from "../../api/baseUrl";
import timestampToTime from "../../utils/timestampToTime";

Vue.use(Toast);
export default {
@@ -59,7 +55,11 @@ export default {
HeadTop,
},
data() {
return {};
return {
videoList: [],
currentPage: 1,
total: "",
};
},
computed: {
...mapState({
@@ -73,21 +73,57 @@ export default {
go(url) {
this.$router.push(url);
},
getVideoList() {

changeTime(timestamp, form) {
return timestampToTime(timestamp, form);
},

pageChange() {
this.getVideoList(this.currentPage);
},

goDetail(item) {
const status = item.videoStatus;
if (status == 0) {
this.$router.push({
path: "/getPaper",
query: {
id: item.id,
},
});
} else if (status == 1) {
Toast.fail("视频生成中");
return;
} else if (status == 2) {
this.$router.push({
path: "/downloadVideo",
query: {
videoDetail: item,
},
});
} else if (status == 3) {
}
},

getVideoList(pageNum) {
const AccessToken = localStorage.getItem("AccessToken");
this.$axios({
method: "get",
url: `${baseUrl}/api/userVideo/list?pageNum=1&pageSize=3`,
url: `${baseUrl}/api/userVideo/list?pageNum=${pageNum}&pageSize=3`,
headers: {
"Content-Type": "application/json;charset=UTF-8",
token: AccessToken,
},
})
.then((res) => {
console.log(res.data);
if (res.data.code == 1052) {
this.$router.push("/login");
Toast.fail("登录过期,请重新登录!");
return;
}
this.videoList = res.data.data.list;
this.total = res.data.data.total;
})
.catch((err) => {
Toast.fail(err.message);
@@ -99,7 +135,7 @@ export default {
},
},
created() {
this.getVideoList();
this.getVideoList(1);
},
};
</script>
@@ -133,6 +169,9 @@ export default {
}
}
}
.showIMG {
width: 100%;
}
.item {
padding: 15px;
.title {
@@ -141,11 +180,20 @@ export default {
}
.itemList {
.videoModel {
position: relative;
display: flex;
justify-content: space-between;
margin-bottom: 20px;
margin-bottom: 25px;
border: 1px solid #0000003a;
border-radius: 5px;
padding: 25px;
.videoPrv {
width: 320px;
width: 100px;
height: 100px;
video {
width: 100%;
height: 100%;
}
}
.videoInfo {
display: flex;
@@ -159,12 +207,38 @@ export default {
font-size: 11px;
}
}
.tag {
position: absolute;
right: 10px;
top: 10px;
padding: 1px 5px;
border-radius: 5px;
&.text {
color: #fff;
background-color: #a2a2a290;
}
&.generating {
background-color: #ffa600c2;
}
&.finish {
color: #ffffff;
background-color: #00ff88;
}
&.fail {
color: #ffffff;
background-color: #ff0000c3;
}
}
}
.noWork {
font-size: 20px;
text-align: center;
}
}
}
.goAdd {
position: fixed;
bottom: 50px;
bottom: 30px;
left: 50%;
width: 300px;
height: 30px;


Carregando…
Cancelar
Salvar