| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551 |
- <template>
- <div class="mirror-setting" v-if="!isNotFound">
- <!-- 图片预览 -->
- <el-dialog v-model="dialogVisible">
- <img
- v-if="checkSourceIsImage(dialogImageUrl) && dialogVisible"
- style="width: 100%; height: 500px; object-fit: scale-down"
- w-full
- :src="dialogImageUrl"
- alt="Preview Image"
- />
- <video
- v-if="checkSourceIsVideo(dialogImageUrl) && dialogVisible"
- style="width: 100%"
- w-full
- controls
- :src="dialogImageUrl"
- />
- <audio
- v-if="checkSourceIsAudio(dialogImageUrl) && dialogVisible"
- style="width: 100%"
- w-full
- controls
- :src="dialogImageUrl"
- />
- </el-dialog>
- <!-- 分镜配置 -->
- <div class="project-title">
- <el-input
- class="title"
- type="textarea"
- :autosize="{ minRows: 1, maxRows: 4 }"
- v-model="project.title"
- />
- <el-button type="primary" @click="saveProject">保存</el-button>
- </div>
- <div class="content">
- <el-table
- :key="data.list.length"
- class="main-table"
- key="id"
- border
- v-dragable="dragOptions"
- :data="data.list"
- header-row-class-name="t-head"
- header-cell-class-name="t-cell"
- >
- <!-- <template v-for="item in columns" :key="item.prop">
- <el-table-column :prop="item.prop" :label="item.label" />
- 大纲
- </template>
- :on-preview="handlePictureCardPreview" :on-remove="handleRemove"
- -->
- <el-table-column prop="name" label="大纲">
- <template v-slot="{ row }">
- <el-input
- type="textarea"
- :autosize="{ minRows: 3 }"
- v-model="row.name"
- :row="3"
- placeholder="概括拍摄内容"
- />
- </template>
- </el-table-column>
- <el-table-column prop="desc" label="分镜描述">
- <template v-slot="{ row }">
- <el-input
- class="gray"
- type="textarea"
- :autosize="{ minRows: 3 }"
- v-model="row.desc"
- :row="3"
- placeholder="详细描述分镜"
- />
- </template>
- </el-table-column>
- <!-- show-overflow-tooltip -->
- <el-table-column prop="clip" label="已拍摄片段">
- <template v-slot="{ row }">
- <el-upload
- ref="upload"
- v-model:file-list="row.fileList"
- class="list-upload-style"
- :accept="DrawFormats.toString()"
- :class="{
- activefileList: row.fileList && row.fileList.length == 1,
- }"
- :before-upload="beforeUpload"
- list-type="picture-card"
- :action="uploadFileUrl"
- :on-success="handleUploadSuccess"
- :limit="1"
- >
- <div
- class="uploadImg"
- v-if="row.fileList && row.fileList.length == 0"
- >
- <el-icon><Plus /></el-icon>
- </div>
- <template #file="{ file }">
- <div style="width: 100%">
- <img
- v-if="file.cover"
- class="el-upload-list__item-thumbnail"
- :src="getCoverUrl(file.cover)"
- alt=""
- />
- <span class="el-upload-list__item-actions">
- <span
- class="el-upload-list__item-preview"
- @click="handlePictureCardPreview(file)"
- >
- <el-icon><zoom-in /></el-icon>
- </span>
- <span
- class="el-upload-list__item-delete"
- @click="handleRemove(row)"
- >
- <el-icon><Delete /></el-icon>
- </span>
- </span>
- </div>
- </template>
- </el-upload>
- </template>
- </el-table-column>
- <el-table-column prop="words" label="台词文案">
- <template v-slot="{ row }">
- <el-input
- class="gray"
- type="textarea"
- :autosize="{ minRows: 3 }"
- v-model="row.words"
- placeholder="点击输入台词"
- />
- </template>
- </el-table-column>
- <el-table-column prop="marks" label="备注">
- <template v-slot="{ row, $index }">
- <div class="marksDiv">
- <el-input
- class="gray"
- type="textarea"
- :autosize="{ minRows: 3 }"
- v-model="row.marks"
- placeholder="点击输入内容"
- />
- <span
- class="table-delete"
- @click="handleTableRemove($index, row)"
- >
- <el-icon><Delete /></el-icon>
- </span>
- </div>
- </template>
- </el-table-column>
- </el-table>
- </div>
- <div class="add-handle">
- <el-button type="primary" @click="handleAdd">
- <el-icon class="el-icon--right">
- <Plus />
- </el-icon>
- 添加
- <el-input class="add-line" type="text" v-model="addLine" size="small">
- </el-input>
- 行
- </el-button>
- </div>
- </div>
- <noCase :show-btn="false" v-else></noCase>
- </template>
- <script lang="ts" setup>
- import { vDragable } from "./dragable";
- import { ElMessage } from "element-plus";
- import { reactive, ref, onMounted, computed } from "vue";
- import type { UploadFile } from "element-plus";
- import { uploadFile as uploadFileUrl } from "@/request";
- import {
- getCaseScriptInfo,
- CaseScriptSaveOrUpdate,
- CaseScriptGetCover,
- } from "@/app/mirror/store/script";
- import linkIco from "@/assets/image/fire.ico";
- import musicHeadphones from "@/assets/image/music.png";
- import { getCaseInfo } from "@/store/case";
- import noCase from "@/view/case/no-case.vue";
- const link = document.querySelector<HTMLLinkElement>("#app-icon")!;
- link.setAttribute("href", linkIco);
- const caseId = ref(null);
- const project = reactive({
- title: "",
- });
- const DrawFormats = [".jpg", ".jpeg", ".png",".mp4",".m4v",".mp3",".aac", ".wav"]
- const isNotFound = ref(false);
- const dialogImageUrl = ref("");
- const dialogVisible = ref(false);
- const disabled = ref(false);
- const addLine = ref(1);
- const active = ref(1);
- const dragOptions = [
- // {
- // selector: "thead tr", // add drag support for column
- // option: {
- // // sortablejs's option
- // animation: 150,
- // onEnd: (evt) => {
- // let oldCol: any = {};
- // Object.assign(oldCol, columns.value[evt.oldIndex]);
- // columns.value.splice(evt.oldIndex, 1); // 因为新增了数据,所以要移除原来的列的index要在原来的基础上
- // setTimeout(() => {
- // columns.value.splice(evt.newIndex, 0, oldCol); // 把原来的列数据添加到新的位置,然后再从原位置移除它,触发table的重绘
- // }, 30);
- // console.log(evt.oldIndex, evt.newIndex);
- // },
- // },
- // },
- {
- selector: "tbody", // add drag support for row
- option: {
- // sortablejs's option
- animation: 150,
- onEnd: (evt: any) => {
- // let oldItem = sortList.value[evt.oldIndex];
- // let sortLists = sortList.value.filter(
- // (_, index) => index !== evt.oldIndex
- // );
- // sortLists.splice(evt.newIndex, 0, oldItem);
- // sortList.value = sortLists;
- let list = JSON.parse(JSON.stringify(data.newSortList));
- const target = list.splice(evt.oldIndex, 1);
- list.splice(evt.newIndex, 0, target[0]);
- data.newSortList = list;
- console.log(evt.oldIndex, evt.newIndex, data.newSortList, data.list);
- },
- },
- },
- ];
- const columns = ref([
- // { prop: "id", label: "ID", hidden: true, },
- { prop: "name", label: "大纲" },
- { prop: "desc", label: "分镜描述" },
- { prop: "clip", label: "已拍摄片段" },
- { prop: "words", label: "台词文案" },
- { prop: "marks", label: "备注" },
- ]);
- const beforeUpload = async (file: File) => {
- const fileType = file.name
- .substring(file.name.lastIndexOf("."))
- .toUpperCase();
- if (!DrawFormats.some((type) => type.toUpperCase() === fileType)) {
- ElMessage.error(`请上传${DrawFormats}格式的文件`);
- return false;
- } else {
- return true;
- }
- };
- const checkSourceIsVideo = computed(() => (url: string) => {
- return url.includes(".mp4") || url.includes(".m4v");
- });
- const checkSourceIsAudio = computed(() => (url: string) => {
- return url.includes(".mp3") || url.includes(".aac") || url.includes(".wav");
- });
- const checkSourceIsImage = computed(() => (url: string) => {
- return url.includes(".jpg") || url.includes(".png") || url.includes(".jpeg") || url.includes(".gif");
- });
- const getCoverUrl = computed(() => (url: string) => {
- switch (true) {
- // case url.includes(".mp4"):
- // return (
- // url + "?x-oss-process=video/snapshot,t_0,f_jpg,w_0,h_0,m_fast,ar_auto"
- // );
- case url.includes(".mp3") || url.includes(".aac") || url.includes(".wmv") || url.includes(".wav"):
- return musicHeadphones;
- default:
- return url;
- }
- });
- const data = reactive({
- list: [{ id: 1, name: "", desc: "", fileList: [] }],
- newSortList: [],
- });
- const sortList = ref([0]);
- onMounted(async () => {
- caseId.value = GetRequest("caseId");
- try {
- const caseInfo = await getCaseInfo(caseId.value!);
- if (caseInfo && caseId.value) {
- document.title = caseInfo.caseTitle + " | 分镜配置";
- } else {
- isNotFound.value = true;
- }
- } catch (error) {
- isNotFound.value = true;
- }
- getCaseScriptList();
- console.log("caseId", caseId); //query传参
- });
- function getCaseScriptList() {
- getCaseScriptInfo(caseId.value)
- .then((res) => {
- project.title = res.name || '我的脚本';
- data.list = res.content || [];
- data.newSortList = res.content || [];
- const idList = data.list.map((ele) => ele.id);
- active.value = idList.length == 0 ? 0 : Math.max.apply(null, idList) || 1;
- sortList.value = data.list.map((_, index) => index);
- console.log("getCaseScriptList", idList, active.value);
- Array.from(data.list).forEach((item) => {
- item.fileList.forEach(async (file: File, index) => {
- if ((file as any).url.includes(".mp4") || (file as any).url.includes(".m4v")) {
- const res = await CaseScriptGetCover((file as any).url);
- (item.fileList[index] as any).cover = res;
- } else {
- (item.fileList[index] as any).cover = (file as any).url;
- }
- });
- });
- })
- .catch((err) => {
- console.log(err);
- });
- }
- function handleAdd() {
- // let content = sortList.value.map((index) => data.list[index]);
- // data.list.length = 0;
- // Object.assign(data.list, content);
- console.log("add", data.newSortList);
- for (var i = 1; i <= addLine.value; i++) {
- console.log(i);
- data.newSortList.push({
- id: active.value + 1,
- name: "",
- desc: "",
- words: "",
- marks: "",
- fileList: [],
- });
- }
- active.value++;
- data.list = data.newSortList;
- sortList.value = data.list.map((_, index) => index);
- }
- const handleRemove = (data) => {
- data.fileList = [];
- };
- const handleTableRemove = (index, datas) => {
- data.newSortList = data.newSortList.filter((ele) => ele.id !== datas.id);
- console.log("saveProject", data.newSortList);
- data.list = data.newSortList;
- // let content = sortList.value.map((index) => data.list[index]);
- // data.list.length = 0;
- // content.splice(index, 1);
- // Object.assign(data.list, content);
- // sortList.value = content.map((_, index) => index);
- ElMessage.success("删除成功");
- console.log("saveProject", index, datas, data.list);
- };
- const handlePictureCardPreview = (file: UploadFile) => {
- dialogImageUrl.value = file.url!;
- dialogVisible.value = true;
- };
- const saveProject = () => {
- // let content = sortList.value.map((index) => data.list[index]);
- let apiDataList = data.newSortList.map((item) => {
- let asData = data.list.find(ele => ele.id === item.id) || {};
- return {
- ...item,
- ...asData,
- }
- });
- console.log("saveProject", data.list, data.newSortList);
- CaseScriptSaveOrUpdate({
- caseId: caseId.value,
- name: project.title,
- content: apiDataList,
- }).then((res) => {
- console.log("saveProject");
- ElMessage.success("保存成功");
- });
- };
- async function handleUploadSuccess(response: any, uploadFile: UploadFile) {
- uploadFile.url = response.data;
- console.log("handleUploadSuccess", uploadFile.url);
- if (uploadFile.url!.includes(".mp4")) {
- const res = await CaseScriptGetCover(uploadFile.url!);
- (uploadFile as any).cover = res;
- } else {
- (uploadFile as any).cover = uploadFile.url;
- }
- }
- function GetRequest(value) {
- var url = decodeURI(window.location.search); //?id="123456"&name="www";
- var object = {};
- if (url.indexOf("?") != -1) {
- //url中存在问号,也就说有参数。
- var str = url.substr(1); //得到?后面的字符串
- var strs = str.split("&"); //将得到的参数分隔成数组[id="123456",name="www"];
- for (var i = 0; i < strs.length; i++) {
- object[strs[i].split("=")[0]] = strs[i].split("=")[1]; //得到{id:'123456',name:'www'}
- }
- }
- return object[value];
- }
- </script>
- <style lang="scss" scoped></style>
- <style lang="scss">
- body,
- #app {
- margin: 0;
- padding: 0;
- }
- .mirror-setting {
- width: 100%;
- min-height: 100%;
- padding-top: 80px;
- min-height: calc(100vh - 80px);
- margin: 0 auto;
- background: #eee;
- .content {
- margin: 0 auto;
- display: flex;
- padding: 0 40px;
- }
- .t-head {
- border: 1px solid #ddd;
- /* padding: 10px; */
- /* display: flex; */
- position: relative;
- background-color: #eee;
- }
- tbody {
- /* border-top: 20px solid transparent; */
- }
- .t-head th {
- margin-bottom: 20px;
- }
- .project-title {
- display: flex;
- padding: 0 40px;
- align-items: center;
- /* justify-content: center; */
- }
- .project-title .title {
- font-size: 28px;
- min-height: 0;
- height: auto;
- background-color: transparent !important;
- /* width: 300px; */
- margin: 30px 0;
- }
- .el-textarea__inner {
- background-color: transparent;
- box-shadow: none;
- resize: none;
- }
- .gray .el-textarea__inner {
- background: rgba(227, 225, 225, 0.2);
- }
- .add-handle {
- padding: 30px 0;
- display: flex;
- justify-content: center;
- }
- .add-line {
- margin: 0 10px;
- width: 30px;
- }
- .add-line .el-input__wrapper {
- box-shadow: none;
- background: rgba(23, 41, 46, 0.2);
- }
- .add-line input {
- color: white;
- text-align: center;
- }
- .activefileList {
- .el-upload-list--picture-card {
- }
- .el-upload--picture-card {
- display: none;
- }
- }
- .list-upload-style {
- width: 100%;
- text-align: center;
- .el-upload-list,
- .el-upload--text {
- width: 100%;
- }
- .el-upload-list__item-thumbnail,
- .el-upload--picture-card {
- min-height: 73px;
- height: 73px;
- width: 100%;
- }
- .uploadImg,
- .el-upload-list__item {
- width: 100%;
- min-height: 73px;
- height: 73px;
- line-height: 73px;
- .el-upload-list__item-thumbnail {
- width: 100%;
- max-width: 100px;
- object-fit: cover;
- }
- }
- }
- .marksDiv {
- position: relative;
- .table-delete {
- position: absolute;
- right: -10px;
- top: -3px;
- }
- }
- }
- </style>
|