|
@@ -1,6 +1,12 @@
|
|
|
+import Empty from "@/components/Empty";
|
|
|
+import { TimeController } from "@/controllers/TimeController";
|
|
|
+import Slider from "@/modules/editor/components/CompUI/formItems/Slider";
|
|
|
import { useResource } from "@/modules/resource";
|
|
|
import { Button } from "ant-design-vue";
|
|
|
-import { defineComponent, reactive } from "vue";
|
|
|
+import dayjs from "dayjs";
|
|
|
+import { queenApi } from "queenjs";
|
|
|
+import Modal from "queenjs/adapter/vue/components/modal";
|
|
|
+import { defineComponent, reactive, ref } from "vue";
|
|
|
import { object } from "vue-types";
|
|
|
|
|
|
export default defineComponent({
|
|
@@ -9,29 +15,199 @@ export default defineComponent({
|
|
|
},
|
|
|
setup(props) {
|
|
|
const resource = useResource();
|
|
|
+ const videoRef = ref();
|
|
|
+ const previewRef = ref();
|
|
|
+
|
|
|
const state = reactive({
|
|
|
- //
|
|
|
+ duration: 0,
|
|
|
+ startTime: 0,
|
|
|
+ endTime: 0,
|
|
|
+ previewObj: {} as any,
|
|
|
});
|
|
|
|
|
|
- const submit = () => {
|
|
|
- resource.actions.editVideo({
|
|
|
- start: 13,
|
|
|
- end: 15,
|
|
|
+ const editVideo = async () => {
|
|
|
+ if (state.endTime - state.startTime <= 0) {
|
|
|
+ queenApi.messageError("截取时长错误");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ queenApi.showLoading("正在处理……");
|
|
|
+ const data = {
|
|
|
+ start: state.startTime,
|
|
|
+ end: state.endTime,
|
|
|
+ id: props.record._id,
|
|
|
+ };
|
|
|
+ const res = await resource.https.cutVideo(data);
|
|
|
+ const { url, jobId } = res.result;
|
|
|
+
|
|
|
+ const videoStatusCtrl = new TimeController({
|
|
|
+ delayTime: 1000,
|
|
|
+ durationTime: 3000,
|
|
|
+ });
|
|
|
+ videoStatusCtrl
|
|
|
+ .setLoop(async () => {
|
|
|
+ const { result } = await resource.https.queryVideoStatus(jobId);
|
|
|
+ if (result === "SUCCEED") {
|
|
|
+ videoStatusCtrl.stop();
|
|
|
+ queenApi.hideLoading();
|
|
|
+ const souceObj: createSourceType = {
|
|
|
+ file: { url },
|
|
|
+ fileType: "video",
|
|
|
+ from: "cut",
|
|
|
+ };
|
|
|
+ state.previewObj = souceObj;
|
|
|
+ } else if (result === "FAILED") {
|
|
|
+ videoStatusCtrl.stop();
|
|
|
+ queenApi.hideLoading();
|
|
|
+ queenApi.messageError("失败,重新提交!");
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .start();
|
|
|
+ };
|
|
|
+
|
|
|
+ const createNew = async () => {
|
|
|
+ queenApi.showLoading("正在创建……");
|
|
|
+ await resource.https.createResource(state.previewObj);
|
|
|
+ setTimeout(async () => {
|
|
|
+ await resource.controls.custVideoListCtrl.loadPage(1);
|
|
|
+ Modal.clear();
|
|
|
+ queenApi.hideLoading();
|
|
|
+ }, 800);
|
|
|
+ };
|
|
|
+
|
|
|
+ const replaceVideo = async () => {
|
|
|
+ queenApi.showLoading("正在替换……");
|
|
|
+ const res = await resource.https.updateVideoUrl({
|
|
|
+ url: state.previewObj.file.url,
|
|
|
id: props.record._id,
|
|
|
});
|
|
|
+ setTimeout(async () => {
|
|
|
+ // eslint-disable-next-line vue/no-mutating-props
|
|
|
+ props.record.thumbnail = res.result.thumbUrl;
|
|
|
+ // eslint-disable-next-line vue/no-mutating-props
|
|
|
+ props.record.file.url = state.previewObj.file.url;
|
|
|
+ Modal.clear();
|
|
|
+ queenApi.hideLoading();
|
|
|
+ }, 800);
|
|
|
};
|
|
|
|
|
|
+ function changeStart(v: number) {
|
|
|
+ videoRef.value.currentTime = v;
|
|
|
+ state.startTime = v;
|
|
|
+ if (state.endTime < state.startTime) {
|
|
|
+ state.endTime = state.startTime + 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function changeEnd(v: number) {
|
|
|
+ // videoRef.value.currentTime = v;
|
|
|
+ state.endTime = v;
|
|
|
+ }
|
|
|
+
|
|
|
+ function formateTime(time: number) {
|
|
|
+ // @ts-ignore
|
|
|
+ const h = parseInt(time / 3600);
|
|
|
+ // @ts-ignore
|
|
|
+ const minute = parseInt((time / 60) % 60);
|
|
|
+ const second = Math.ceil(time % 60);
|
|
|
+
|
|
|
+ const hours = h < 10 ? "0" + h : h;
|
|
|
+ const formatSecond = second > 59 ? 59 : second;
|
|
|
+ // @ts-ignore
|
|
|
+ return `${hours > 0 ? `${hours}:` : ""}${
|
|
|
+ minute < 10 ? "0" + minute : minute
|
|
|
+ }:${formatSecond < 10 ? "0" + formatSecond : formatSecond}`;
|
|
|
+ }
|
|
|
+
|
|
|
return () => {
|
|
|
const { record } = props;
|
|
|
- // console.log("record: ", record);
|
|
|
+ const { duration, startTime, endTime, previewObj } = state;
|
|
|
+ const submitDisabled = previewObj.file ? false : true;
|
|
|
+
|
|
|
return (
|
|
|
<div>
|
|
|
- <div>
|
|
|
- <video src={record.file?.url} class="w-full" controls />
|
|
|
+ <div class="flex items-center justify-center space-x-30px overflow-hidden">
|
|
|
+ <div>
|
|
|
+ <div class="mb-20px">原视频</div>
|
|
|
+ <div class="flex items-center justify-center w-510px h-400px bg-[#1B1B1B] rounded">
|
|
|
+ <video
|
|
|
+ controls
|
|
|
+ ref={videoRef}
|
|
|
+ src={record.file?.url}
|
|
|
+ class="w-full"
|
|
|
+ onLoadeddata={() => {
|
|
|
+ const time = videoRef.value.duration;
|
|
|
+ state.duration = Math.floor(time);
|
|
|
+ videoRef.value.volume = videoRef.value.volume / 2;
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <div class="mb-20px">剪辑后预览</div>
|
|
|
+ <div class="flex items-center justify-center w-510px h-400px bg-[#1B1B1B] rounded">
|
|
|
+ {previewObj.file?.url ? (
|
|
|
+ <video
|
|
|
+ controls
|
|
|
+ ref={previewRef}
|
|
|
+ src={previewObj.file?.url}
|
|
|
+ class="w-full"
|
|
|
+ onLoadeddata={() => {
|
|
|
+ previewRef.value.volume = previewRef.value.volume / 2;
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ ) : (
|
|
|
+ <Empty />
|
|
|
+ )}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="mt-50px font-bold text-14px">剪辑</div>
|
|
|
+ <div class="flex items-center justify-around h-60px mt-20px rounded bg-[#1B1B1B]">
|
|
|
+ <div class="flex items-center justify-between space-x-20px">
|
|
|
+ <span class="text-12px">启始时间</span>
|
|
|
+ <Slider
|
|
|
+ min={0}
|
|
|
+ max={duration}
|
|
|
+ value={startTime}
|
|
|
+ class="w-300px"
|
|
|
+ onChange={changeStart}
|
|
|
+ formatter={(v) => formateTime(v)}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="flex items-center justify-between space-x-20px">
|
|
|
+ <span class="text-12px">结束时间</span>
|
|
|
+ <Slider
|
|
|
+ min={0}
|
|
|
+ max={duration}
|
|
|
+ value={endTime}
|
|
|
+ class="w-300px"
|
|
|
+ onChange={changeEnd}
|
|
|
+ formatter={(v) => formateTime(v)}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <Button type="primary" class="w-100px" onClick={editVideo}>
|
|
|
+ 生成视频
|
|
|
+ </Button>
|
|
|
</div>
|
|
|
- <div>
|
|
|
- <Button type="primary" onClick={submit}>
|
|
|
- 提交
|
|
|
+ <div class="mt-60px text-center space-x-30px">
|
|
|
+ <Button
|
|
|
+ ghost
|
|
|
+ type="primary"
|
|
|
+ size="large"
|
|
|
+ class="w-300px"
|
|
|
+ disabled={submitDisabled}
|
|
|
+ onClick={replaceVideo}
|
|
|
+ >
|
|
|
+ 替换原视频
|
|
|
+ </Button>
|
|
|
+ <Button
|
|
|
+ type="primary"
|
|
|
+ size="large"
|
|
|
+ class="w-300px"
|
|
|
+ disabled={submitDisabled}
|
|
|
+ onClick={createNew}
|
|
|
+ >
|
|
|
+ 生成新视频
|
|
|
</Button>
|
|
|
</div>
|
|
|
</div>
|