342 lines
9.8 KiB
Vue
342 lines
9.8 KiB
Vue
<template>
|
||
<div class="layout-pd">
|
||
<el-card v-loading="state.loading" shadow="hover" header="视频详情">
|
||
<el-form ref="videoFormRef" :model="state.data" :rules="state.rules" size="large" label-width="100px" class="mt20 mb20">
|
||
<el-row :gutter="35">
|
||
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
|
||
<el-form-item label="模块名称:" prop="moduleName">
|
||
<el-select size="default" @change="handleChangeModule" v-model="state.data.moduleName" placeholder="请选择模块" clearable>
|
||
<el-option
|
||
:data-op="item.id"
|
||
v-for="(item, index) in moduleList"
|
||
:key="index"
|
||
:label="item.moduleName"
|
||
:value="item.moduleName"
|
||
></el-option>
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
|
||
<el-form-item label="标签名称:" prop="labelName">
|
||
<el-select size="default" v-model="state.data.labelName" placeholder="请选择标签" clearable class="ml10">
|
||
<el-option v-for="(item, index) in labelList" :key="index" :label="item.name" :value="item.name"></el-option>
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
|
||
<el-form-item label="视频名称:" prop="name">
|
||
<el-input v-model="state.data.name" placeholder="请输入标题" clearable></el-input>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
|
||
<el-form-item label="视频:" prop="path" class="coverImg">
|
||
<!-- 上传文件 -->
|
||
<el-upload
|
||
ref="uploadRef"
|
||
class="h100 personal-user-left-upload"
|
||
action="#"
|
||
list-type="picture-card"
|
||
:file-list="state.fileArray"
|
||
:auto-upload="false"
|
||
:limit="1"
|
||
:class="{ hide: state.coverHide }"
|
||
@change="handleUploadChange"
|
||
accept="video/*"
|
||
>
|
||
<template #default>
|
||
<el-icon><Plus /></el-icon>
|
||
</template>
|
||
<template #file="{ file }">
|
||
<div>
|
||
<!-- class="el-upload-list__item-thumbnail" -->
|
||
<video style="width: 100%; height: auto; border-radius: 4px" :src="file.url"></video>
|
||
<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 v-if="!disabled" class="el-upload-list__item-delete" @click="handleRemove(file)">
|
||
<el-icon><Delete /></el-icon>
|
||
</span>
|
||
</span>
|
||
</div>
|
||
</template>
|
||
</el-upload>
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
<el-row class="flex mt15">
|
||
<div class="flex-margin" style="width: 100%; display: flex; justify-content: flex-end">
|
||
<el-button size="larger" type="info" @click="cancel">
|
||
<SvgIcon name="ele-RefreshLeft" />
|
||
取消
|
||
</el-button>
|
||
<el-button size="larger" type="primary" @click="onSubmitForm">
|
||
<SvgIcon name="iconfont icon-shuxing" />
|
||
保存
|
||
</el-button>
|
||
</div>
|
||
</el-row>
|
||
</el-form>
|
||
</el-card>
|
||
<!-- 视频预览弹窗 -->
|
||
<el-dialog v-model="dialogVisible">
|
||
<video style="width: 100%; height: auto; border-radius: 4px" :src="dialogVideoUrl" controls></video>
|
||
</el-dialog>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts" name="editVideo">
|
||
import { onMounted, reactive, ref } from 'vue';
|
||
import { articleApi } from '/@/api/article';
|
||
import { videoApi } from '/@/api/video';
|
||
import { useRoute, useRouter } from 'vue-router';
|
||
import { ElMessage, UploadFile, UploadFiles } from 'element-plus';
|
||
import { Delete, Plus, ZoomIn } from '@element-plus/icons-vue';
|
||
import mittBus from '/@/utils/mitt';
|
||
|
||
// 视频基本路径
|
||
const viteUrl = import.meta.env.VITE_API_URL;
|
||
|
||
// 引入 api 请求接口
|
||
const artApi = articleApi();
|
||
const vidApi = videoApi();
|
||
|
||
// 模块列表
|
||
const moduleList = ref<{ id: number; moduleName: string }[]>([]);
|
||
|
||
// 标签列表
|
||
const labelList = ref<{ name: string }[]>([]);
|
||
|
||
// 获取视频id
|
||
const route = useRoute();
|
||
const router = useRouter();
|
||
const moduleName: any = route.query.moduleName;
|
||
const labelName: any = route.query.labelName;
|
||
const id: any = route.query.id;
|
||
|
||
const state = reactive({
|
||
data: {
|
||
labelName: '',
|
||
moduleName: '',
|
||
name: '',
|
||
path: '',
|
||
},
|
||
loading: false,
|
||
rules: {
|
||
moduleName: { required: true, message: '请选择模块', trigger: 'blur' },
|
||
labelName: { required: true, message: '请输入标签名称', trigger: 'blur' },
|
||
name: { required: true, message: '请输入标题', trigger: 'blur' },
|
||
path: { required: true, message: '请上传视频', trigger: 'blur' },
|
||
},
|
||
fileArray: [], // 编辑进来时,如果已经上传了视频,则保存视频地址
|
||
coverFile: {},
|
||
coverHide: false,
|
||
});
|
||
|
||
// 模块选择
|
||
const handleChangeModule = async (val: any) => {
|
||
try {
|
||
state.data.labelName = '';
|
||
if (!val) {
|
||
labelList.value = [];
|
||
return;
|
||
}
|
||
const op: any = event?.currentTarget;
|
||
let res = await artApi.getLabelList(op.dataset.op);
|
||
if (res?.success) {
|
||
labelList.value = res.data;
|
||
} else {
|
||
ElMessage.error('标签列表获取失败!');
|
||
}
|
||
} catch (error) {
|
||
ElMessage.error('标签列表获取失败!');
|
||
} finally {
|
||
}
|
||
};
|
||
|
||
// 获取视频详情
|
||
const getVideoDetail = async () => {
|
||
try {
|
||
state.loading = true;
|
||
let res = await vidApi.getVideoList({
|
||
moduleName: moduleName,
|
||
labelName: labelName,
|
||
size: 1,
|
||
current: 1,
|
||
});
|
||
if (res?.success) {
|
||
state.data = res.data.records[0];
|
||
// 下面这里处理一下,因为后端返回的是0和1,而前端需要的是true和false,到时候提交的时候再转换回来
|
||
// 这个报错没关系的,只是ts的语法检查,不影响运行
|
||
if (state.data.path) {
|
||
const never: any = [{ name: state.data.name, url: viteUrl + state.data.path }];
|
||
state.fileArray = never;
|
||
state.coverHide = true;
|
||
}
|
||
}
|
||
} catch (error) {
|
||
ElMessage.error('获取视频详情失败');
|
||
} finally {
|
||
state.loading = false;
|
||
}
|
||
};
|
||
|
||
// 获取视频详情-根据id
|
||
const getVideoDetailById = async (id: number) => {
|
||
try {
|
||
state.loading = true;
|
||
let res = await vidApi.getVideoDetail(id);
|
||
if (res?.success) {
|
||
state.data = res.data;
|
||
// 下面这里处理一下,因为后端返回的是0和1,而前端需要的是true和false,到时候提交的时候再转换回来
|
||
// 这个报错没关系的,只是ts的语法检查,不影响运行
|
||
state.data.moduleName = moduleName;
|
||
state.data.labelName = labelName;
|
||
if (state.data.path) {
|
||
const never: any = [{ name: state.data.name, url: viteUrl + state.data.path }];
|
||
state.fileArray = never;
|
||
state.coverHide = true;
|
||
}
|
||
}
|
||
} catch (error) {
|
||
ElMessage.error('获取视频详情失败');
|
||
} finally {
|
||
state.loading = false;
|
||
}
|
||
};
|
||
|
||
// 获取模块列表
|
||
const getModuleList = async () => {
|
||
try {
|
||
let res = await artApi.getModuleList();
|
||
if (res?.success) {
|
||
moduleList.value = res.data;
|
||
} else {
|
||
ElMessage.error('模块列表获取失败!');
|
||
}
|
||
} catch (error) {
|
||
ElMessage.error('模块列表获取失败!');
|
||
} finally {
|
||
}
|
||
};
|
||
|
||
const videoFormRef = ref();
|
||
|
||
// 保存视频,在新增视频时不会调用以下函数
|
||
const onSubmitForm = () => {
|
||
videoFormRef.value.validate((valid: boolean) => {
|
||
if (valid && state.coverHide) {
|
||
const form = { ...state.data };
|
||
if (state.coverFile.type === undefined) {
|
||
realSubmit(form);
|
||
} else {
|
||
uploadFile(state.coverFile, form);
|
||
}
|
||
} else {
|
||
ElMessage.error('请完善信息!');
|
||
}
|
||
});
|
||
};
|
||
|
||
// 返回
|
||
const cancel = () => {
|
||
mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 1, ...route }));
|
||
router.push('/video');
|
||
};
|
||
|
||
// 上传文件
|
||
const uploadFile = async (file: any, form: any) => {
|
||
try {
|
||
state.loading = true;
|
||
const formdata = new FormData();
|
||
formdata.append('file', file);
|
||
formdata.append('type', 'video');
|
||
|
||
let res = await vidApi.uploadFileType(formdata);
|
||
if (res?.success) {
|
||
form.path = res.data;
|
||
realSubmit(form);
|
||
} else {
|
||
ElMessage.error('视频上传失败!');
|
||
}
|
||
} catch (error) {
|
||
state.loading = false;
|
||
ElMessage.error('视频上传失败!');
|
||
}
|
||
};
|
||
|
||
// 视频上传-真正的上传操作
|
||
const realSubmit = async (form: any) => {
|
||
try {
|
||
state.loading = true;
|
||
let res = route.path == '/video/add' ? await vidApi.saveVideo(form) : await vidApi.updateVideo(form);
|
||
if (res?.success) {
|
||
ElMessage.success('视频保存成功!');
|
||
cancel();
|
||
} else {
|
||
ElMessage.error('视频保存失败!');
|
||
}
|
||
} catch (error) {
|
||
ElMessage.error('处理失败!');
|
||
} finally {
|
||
state.loading = false;
|
||
}
|
||
};
|
||
|
||
// 视频上传禁用
|
||
const disabled = ref(false);
|
||
// 视频弹窗
|
||
const dialogVideoUrl = ref('');
|
||
const dialogVisible = ref(false);
|
||
|
||
const uploadRef = ref();
|
||
|
||
// 视频删除
|
||
const handleRemove = (file: UploadFile) => {
|
||
state.coverFile = {};
|
||
uploadRef.value.clearFiles();
|
||
state.coverHide = false;
|
||
};
|
||
|
||
// 视频预览
|
||
const handlePictureCardPreview = (file: UploadFile) => {
|
||
dialogVideoUrl.value = file.url!;
|
||
dialogVisible.value = true;
|
||
};
|
||
|
||
// 视频更改
|
||
const handleUploadChange = (uploadFile: UploadFile, uploadFiles: UploadFiles) => {
|
||
if (uploadFile.raw && uploadFile.raw.type.includes('video')) {
|
||
const file: any = uploadFile.raw;
|
||
state.coverFile = file;
|
||
state.data.path = file.name;
|
||
state.coverHide = true;
|
||
} else {
|
||
ElMessage.error('请上传视频文件!');
|
||
uploadRef.value.clearFiles();
|
||
}
|
||
};
|
||
|
||
onMounted(() => {
|
||
if (moduleName && labelName && route.path == '/video/edit') {
|
||
if (moduleName && moduleName !== '人才模块' && moduleName !== '简历模块') {
|
||
getVideoDetailById(id);
|
||
} else {
|
||
getVideoDetail();
|
||
}
|
||
}
|
||
getModuleList();
|
||
});
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.coverImg :deep(.hide .el-upload--picture-card) {
|
||
display: none;
|
||
}
|
||
|
||
:deep(.el-upload-list--picture-card .el-upload-list__item){
|
||
width: 100%;
|
||
}
|
||
</style>
|
||
|