PixelAI-admin/src/views/article/component/upload.vue
2024-11-12 17:35:06 +08:00

363 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="layout-pd">
<el-card v-loading="state.loading" shadow="hover" header="文章详情">
<el-form ref="articleFormRef" :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="封面:" 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='image/*'>
<template #default>
<el-icon><Plus /></el-icon>
</template>
<template #file="{ file }">
<div>
<img class="el-upload-list__item-thumbnail" :src="file.url" 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
v-if="!disabled"
class="el-upload-list__item-delete"
@click="handleDownload(file)"
>
<el-icon><Download /></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-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="title">
<el-input v-model="state.data.title" 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="articletype">
<el-select size="default" v-model="state.data.articletype" placeholder="请选择文章类型" clearable>
<el-option label="图文" :value="0"></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="top">
<el-switch v-model="state.data.top" />
</el-form-item>
</el-col>
</el-row>
<el-form-item prop="text" label-width="0px">
<Editor v-model:get-html="state.data.text" style="width: 100%;"/>
</el-form-item>
<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">
<img width="100%" w-full :src="dialogImageUrl" alt="预览" />
</el-dialog>
</div>
</template>
<script setup lang="ts" name="articleDetail">
import { defineAsyncComponent, onMounted, reactive, ref } from 'vue';
import { articleApi } from '/@/api/article';
import { useRoute, useRouter } from 'vue-router';
import { ElMessage, UploadFile, UploadFiles } from 'element-plus';
import { Delete, Download, Plus, ZoomIn } from '@element-plus/icons-vue';
import mittBus from '/@/utils/mitt';
// 引入组件
const Editor = defineAsyncComponent(() => import('/@/components/editor/index.vue'));
// 封面基本路径
const viteUrl = import.meta.env.VITE_API_URL;
// 引入 api 请求接口
const artApi = articleApi();
// 模块列表
const moduleList = ref([]);
// 标签列表
const labelList = ref([]);
// 获取文章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: '',
title: '',
articletype: '',
photo: '',
text: '',
top: false,// 是否置顶这里提交的时候要换成0或1
},
loading: false,
rules: {
moduleName: { required: true, message: '请选择模块', trigger: 'blur' },
labelName: { required: true, message: '请输入标签名称', trigger: 'blur' },
title: { required: true, message: '请输入标题', trigger: 'blur' },
articletype: { required: true, message: '请选择文章类型', trigger: 'blur' },
photo: { required: true, message: '请上传图片', trigger: 'blur' },
top: { required: true, message: '请选择是否置顶', trigger: 'blur' },
text: { 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 getArticleDetail = async() => {
try {
state.loading = true;
let res = await artApi.getArticleList({
moduleName: moduleName,
labelName: labelName,
size: 1,
current: 1
});
if(res?.success) {
state.data = res.data.records[0];
// 下面这里处理一下因为后端返回的是0和1而前端需要的是true和false到时候提交的时候再转换回来
// 这个报错没关系的只是ts的语法检查不影响运行
state.data.top = state.data.top === 1;
state.data.textid = state.data.id;
if(state.data.photo){
const never:any = [{name:state.data.title,url:viteUrl+state.data.photo}];
state.fileArray = never;
state.coverHide = true;
}
}
} catch (error) {
ElMessage.error('获取文章详情失败');
} finally {
state.loading = false;
}
}
// 获取文章详情-根据id
const getArticleDetailById = async(id:number) => {
try {
state.loading = true;
let res = await artApi.getArticleDetail(id);
if(res?.success) {
state.data = res.data;
// 下面这里处理一下因为后端返回的是0和1而前端需要的是true和false到时候提交的时候再转换回来
// 这个报错没关系的只是ts的语法检查不影响运行
state.data.top = state.data.top === 1;
state.data.moduleName = moduleName;
state.data.labelName = labelName;
state.data.textid = state.data.id;
if(state.data.photo){
const never:any = [{name:state.data.title,url:viteUrl+state.data.photo}];
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 articleFormRef = ref();
// 保存文章
const onSubmitForm = () => {
articleFormRef.value.validate((valid: boolean) => {
if (valid && state.coverHide){
const form = {...state.data,top:state.data.top ? 1 : 0};
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('/article');
}
// 上传文件
const uploadFile = async(file: any,form: any) => {
try {
state.loading = true;
const formdata = new FormData();
formdata.append('file', file);
console.log(file)
let res = await artApi.uploadFile(formdata);
if(res?.success){
form.photo = res.data.path;
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 == '/article/add' ? await artApi.saveArticle(form) : await artApi.updateArticle(form);
if(res?.success){
ElMessage.success('文章保存成功!');
cancel();
}else{
ElMessage.error('文章保存失败!');
}
} catch (error) {
ElMessage.error('处理失败!');
} finally {
state.loading = false;
}
}
// 封面上传禁用
const disabled = ref(false);
// 封面弹窗
const dialogImageUrl = ref('');
const dialogVisible = ref(false);
const uploadRef = ref();
// 封面删除
const handleRemove = (file: UploadFile) => {
state.coverFile = {};
uploadRef.value.clearFiles();
state.coverHide = false;
}
// 封面预览
const handlePictureCardPreview = (file: UploadFile) => {
dialogImageUrl.value = file.url!
dialogVisible.value = true
}
// 封面下载
const handleDownload = (file: UploadFile) => {
console.log(file);
const fileUrl:any = file.url;
// window.location.href = fileUrl;
}
// 封面图片更改
const handleUploadChange = (uploadFile: UploadFile, uploadFiles: UploadFiles) => {
if(uploadFile.raw.type.includes('image')){
const file:any = uploadFile.raw;
state.coverFile = file;
state.coverHide = true;
}else{
ElMessage.error('请上传图片文件!');
uploadRef.value.clearFiles();
}
}
onMounted(() => {
if(moduleName && labelName && route.path == '/article/edit') {
if(moduleName && moduleName !== '人才模块' && moduleName !== '简历模块'){
getArticleDetailById(id);
}else{
getArticleDetail();
}
}
getModuleList();
})
</script>
<style scoped lang="scss">
.coverImg :deep(.hide .el-upload--picture-card) {
display: none;
}
</style>