cankao-admin/src/views/pages/richedit/DetailDrawer/index.vue

750 lines
21 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="[isMobileByWidth() ? 'drawer-container-mobile' : 'drawer-container', { 'drawer-container-100': isFull }]">
<el-drawer v-model="model" :modal="false" size="100%" :lock-scroll="false" modal-class="modal-class">
<template #header>
<div class="drawer-header">
<div class="title">{{ readOnly ? '资讯信息浏览' : type == 1 ? '资讯信息编辑' : '资讯信息创建' }}</div>
<div class="btn" v-if="type == 1">
<!-- <el-button type="text"
v-if="!form.deleted && (data.status == 3 || data.status == -1 || data.status == 4 || data.status == 2) && (Session.get('userInfoLocal').userType == '01' || Session.get('userInfoLocal').userType == '02')"
@click="handleEditStatus(!readOnly)">{{ readOnly ?
'编辑' : '浏览' }}</el-button>
<el-button type="text"
v-else-if="!form.deleted && (data.status == 0 || data.status == 1 || data.status == -1)"
@click="handleEditStatus(!readOnly)">{{ readOnly ?
'编辑' : '浏览' }}</el-button> -->
<!-- <el-button type="text" style="color: #ff1818"
v-if="!form.deleted && (data.status == 0 || data.status == 1 || data.status == -1)"
@click="doDeleteNewsFn(data)">删除</el-button> -->
<div v-if="Session.get('userInfoLocal').userType == '00'">
<el-button type="text" v-if="!form.deleted && (data.status == 1 || data.status == -1)"
@click="handleEditStatus(!readOnly)">{{ readOnly ?
'编辑' : '浏览' }}</el-button>
<el-button type="text" style="color: #ff1818"
v-if="!form.deleted && (data.status == 0 || data.status == 1)"
@click="doDeleteNewsFn(data)">删除</el-button>
</div>
<div v-if="Session.get('userInfoLocal').userType == '02'">
<el-button type="text"
v-if="!form.deleted && (data.status == 0 || data.status == 1 || data.status == 3)"
@click="handleEditStatus(!readOnly)">{{ readOnly ?
'编辑' : '浏览' }}</el-button>
<el-button type="text" style="color: #ff1818"
v-if="!form.deleted && (data.status == 0 || data.status == 1)"
@click="doDeleteNewsFn(data)">删除</el-button>
</div>
<div v-if="Session.get('userInfoLocal').userType == '01'">
<el-button type="text" v-if="!form.deleted && (data.status == 4 || data.status == 2)"
@click="handleEditStatus(!readOnly)">{{ readOnly ?
'编辑' : '浏览' }}</el-button>
<el-button type="text" style="color: #ff1818"
v-if="!form.deleted && (data.status == 0 || data.status == 1)"
@click="doDeleteNewsFn(data)">删除</el-button>
</div>
<el-button type="text" @click="clickFull" v-if="!isMobileByWidth()">
<el-icon v-if="!isFull">
<FullScreen />
</el-icon>
<el-icon v-else>
<Switch />
</el-icon>
</el-button>
</div>
</div>
</template>
<el-form class="form" :rules="rules" ref="ruleFormRef" :model="form" label-width="95">
<div class="center">
<div class="step_bk">
<div v-if="readOnly || type === 1">
<strong>报道时间:</strong>
<span style="color: #0888d7">{{ data.publishTime && formatDate(new Date(data.publishTime),
'YYYY年mm月dd日 HH:MM') }}</span>
</div>
<el-form-item label="标题" style="margin-top: 20px" prop="title" label-width="52">
<div style="display: flex; width: 800px; align-items: center">
<el-input placeholder="输入文章标题" v-model="form.title" :max="titleTextMax"
:maxlength="titleTextMax" @input="inputChange" :disabled="readOnly"></el-input>
<text style="margin-left: 10px; color: #b3b3b3"> {{ titleTextNum }}/{{ titleTextMax
}}</text>
<icon_ai v-if="form.titleTranslated"></icon_ai>
</div>
</el-form-item>
<el-form-item prop="summary" label="摘要" label-width="52">
<el-input v-model="form.summary" show-word-limit maxlength="300" style="margin-top: 10px"
:rows="5" type="textarea" placeholder="请输入摘要内容" max="300" :disabled="readOnly" />
</el-form-item>
</div>
<div class="step_bk">
<el-form-item label="媒体来源:" prop="tagSourceSelect">
<el-select :disabled="readOnly" v-model="form.tagSourceSelect" filterable
placeholder="选择媒体来源" size="large" style="width: 240px">
<el-option v-for="item in tagSourceList" :key="item.id" :label="item.name"
:value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="概念标签:" prop="tagDiySelect">
<el-select :disabled="readOnly" v-model="form.tagDiySelect" filterable multiple
placeholder="选择概念标签" size="large" style="width: 240px">
<el-option v-for="item in tagDiyList" :key="item.id" :label="item.name"
:value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="行业分类:" prop="industrySelect">
<el-select :disabled="readOnly" v-model="form.industrySelect" filterable multiple
placeholder="选择行业分类" size="large" style="width: 240px">
<el-option v-for="item in industryList" :key="item.id" :label="item.name"
:value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="编辑评分:" prop="industrySelect">
<el-rate v-model="form.rating" clearable :disabled="readOnly" />
</el-form-item>
</div>
<div class="step_bk" style="position: relative">
<icon_ai v-if="form.contentTranslated"
style="position: absolute; right: 50px; top: 20px; z-index: 9999">
</icon_ai>
<editorBox :ueditorData="form.content" @changeMsg="changeMsg" :readOnly="readOnly"></editorBox>
<translate v-if="form.newsInfoId && !isMobileByWidth()" :infoData="form" :key="form.id">
</translate>
</div>
<el-collapse accordion expand-icon-position="left"
style="margin-top:10px;padding: 0 30px;border-top: 0;">
<el-collapse-item name="1">
<template #title="{ isActive }">
<div :class="['title-wrapper', { 'is-active': isActive }]">
<text style="font-size: 16px; font-weight: bold">编辑审核备注</text>
</div>
</template>
<el-input v-model="form.revision" show-word-limit maxlength="300" style="margin-top: 10px"
:rows="5" type="textarea" placeholder="请输入编辑审核备注" max="300" :disabled="readOnly" />
</el-collapse-item>
</el-collapse>
</div>
</el-form>
<template #footer>
<div v-if="!readOnly" style="padding: 10px;display: flex;float: right;gap:10px;padding-right: 40px;">
<el-button @click="submit(1, false)">{{ isMobileByWidth() ? '保存并反馈' : '保存' }}</el-button>
<!-- <div v-if="Session.get('userInfoLocal').userType == '00'">
<el-button v-if="data?.status != 3" type="primary" @click="doApprovalFn()">送审</el-button>
<el-button v-else-if="data?.status == 3" type="primary" @click="doApprovalFn()">撤审</el-button>
</div> -->
<el-button
v-if="data?.status == 2 && !form.deleted && Session.get('userInfoLocal').userType == '01'"
type="primary" style="margin-right: 30px;margin-bottom: 20px;"
@click="doNewsPublishFn(data, 1)">撤稿</el-button>
<el-button type="primary" @click="doNewCheckFn(data)"
v-if="data?.status != 2 && !form.deleted && Session.get('userInfoLocal').userType == '02'">复审</el-button>
<el-button type="primary" @click="submit(0, false)"
v-if="data?.status != 2 && data?.status != -1 && !form.deleted && Session.get('userInfoLocal').userType != '02' && Session.get('userInfoLocal').userType == '01'">
<text>发布</text>
</el-button>
<el-button type="primary" @click="doApprovalFn(0, false)"
v-if="data?.status != 2 && (data?.status == -1 || data?.status == 1) && !form.deleted && Session.get('userInfoLocal').userType != '02'">
<text v-if="Session.get('userInfoLocal').userType == '00'">送审</text>
</el-button>
<el-button type="danger"
v-if="Session.get('userInfoLocal').userType == '02' && (data?.status == 3 || data?.status == 4)"
@click="doNewReturnFn(data)">退改</el-button>
<el-button type="danger" v-if="Session.get('userInfoLocal').userType == '01' && (data?.status == 4)"
@click="doNewReturnFn(data)">退改</el-button>
</div>
</template>
</el-drawer>
</div>
</template>
<script setup lang="ts">
import { onMounted, reactive, ref, watch } from 'vue';
import { NextLoading } from '/@/utils/loading';
import { ElMessage, ElStep, ElMessageBox } from 'element-plus';
import { useRoute, useRouter } from 'vue-router';
import editorBox from '/@/components/editorBox.vue';
import uploadImage from '/@/components/upload/image.vue';
import { doNewRevoke, doNewSubmit, getTagSource, getTagConcept, getColumn, doNewsSave, doNewsCreatePublish, getNewsDetail, getColumnVIP, getIndustrySearch } from '/@/api/api';
import { FullScreen, Switch } from '@element-plus/icons-vue';
import { formatDate } from '/@/utils/formatTime';
import icon_ai from '/@/components/icon_ai.vue';
import translate from '/@/components/translate/translate.vue';
import { Session } from '/@/utils/storage';
import { isMobileByWidth } from '/@/utils/Utils'
import { doNewReturn, doNewCheck } from '/@/api/api';
const emit = defineEmits(['doNewsPublishFn', 'handleEditStatus', 'doDeleteNewsFn', 'getData']);
const props = defineProps({
data: {
type: Object,
default: () => { },
},
readOnly: {
type: Boolean,
default: false,
},
type: {
type: Number,
default: 0,
},
});
const model = defineModel();
const loading = ref(false);
const route = useRoute();
const router = useRouter();
const rules = reactive({
title: [{ required: true, message: '请填写文章标题', trigger: 'blur' }],
tagSourceSelect: [{ required: true, message: '请选择来源标签', trigger: 'blur' }],
// columnsVip: [{ required: true, message: '请选择VIP栏目', trigger: 'blur' }],
// tagDiySelect: [{ required: true, message: '请选择标签类型', trigger: 'blur' }],
});
const ruleFormRef = ref();
const form = ref({
type: 0,
column: {
earlyKnow: {
show: true,
},
showEverything: true,
everything: {
type: null,
},
},
rating: 0,
showEverything: true,
});
/********************step1 start *************************/
// 文章标题已经输入的字数
const titleTextNum = ref(0);
// 文章标题最大字数限制
const titleTextMax = ref(50);
function inputChange(text) {
titleTextNum.value = text.length;
}
/********************step1 end *************************/
/********************step2 start *************************/
function changeMsg(value) {
form.value.content = value.html;
form.value.contentText = value.text;
}
/********************step2 end *************************/
/********************step3 start *************************/
// 用户选择的栏目列表
// 栏目选择框数组
// const columnNumList = ref([{}, {}]);
// function addColumnNum() {
// columnNumList.value.push({});
// }
// // 删除新添加的栏目
// function delColunmNum(index: number) {
// columnNumList.value.splice(index, 1);
// }
// 栏目列表(接口获取的待选择列表)
// const columnList1 = ref([]);
// const columnList2 = ref([]);
const columnListVIp = ref([]);
// 获取VIP栏目
async function getColumnVIPFn() {
let { code, data } = await getColumnVIP({
page: 1,
size: 100000,
});
if (code == 200) {
columnListVIp.value = data;
}
}
// // 获取栏目
// async function getColumnFn(type) {
// let { code, data } = await getColumn({
// page: 1,
// size: 100000,
// type,
// });
// if (code == 200) {
// if (type == 0) {
// columnList1.value = data;
// } else {
// columnList2.value = data;
// }
// }
// }
// 用户选择的来源标签(单选)
// const tagSourceSelect = ref();
// 用户选择的标签类型(多选)
// const tagDiySelect = ref([]);
// 自定义标签列表
const tagDiyList = ref([]);
async function getTagDiyFn() {
let { code, data } = await getTagConcept();
if (code == 200) {
tagDiyList.value = data.map((item: any) => {
return {
name: `${item.parentName ? item.parentName + '-' : ''}${item.name ? item.name : ''}`,
id: item.id,
};
});
}
}
// 来源标签列表
const tagSourceList = ref([]);
async function getTagSourceFn() {
let { code, data } = await getTagSource({
page: 1,
size: 100000,
});
if (code == 200) {
tagSourceList.value = data;
}
}
// 行业分类列表
const industryList = ref([]);
async function getTndustryFn() {
let { code, data } = await getIndustrySearch({
page: 1,
size: 100000,
});
if (code == 200) {
industryList.value = data.map((item: any) => {
return {
name: `${item.primaryName || ''}${item.secondaryName ? '-' + item.secondaryName : ''}`,
id: item.id,
};
});
}
}
//展示方式列表
const showTypeList = ref([
{
name: '无特殊样式',
value: null,
},
{
name: '封面banner',
value: 0,
},
{
name: '标题banner',
value: 1,
},
]);
/********************step3 end *************************/
const canSubmit = ref(false);
watch(
() => form.value,
(val) => {
// console.log('🚀 ~ val:', val);
if (form.value.title && form.value.tagSourceSelect && form.value.columnsVip) {
canSubmit.value = true;
}
},
{
immediate: true,
deep: true,
}
);
// 退改
async function doNewReturnFn(item) {
let { code, data } = await doNewReturn({
id: item.id,
});
if (code == 200) {
ElMessage.success('操作成功');
goBack()
}
}
// 复审
async function doNewCheckFn(item) {
let { code, data } = await doNewCheck({
id: item.id,
});
if (code == 200) {
ElMessage.success('操作成功');
goBack()
}
}
const pictureTemp = ref([]);
/**
* 提交创建
* @param type 0发布 1保存
*/
async function submit(type, doNotBack) {
form.value.picture = pictureTemp.value[0]?.url;
if (!form.value.title) {
ElMessage.error('请输入标题');
tabIndex.value = 0;
await ruleFormRef.value.validate();
return;
}
if (!form.value.tagSourceSelect) {
ElMessage.error('请选择来源标签');
tabIndex.value = 2;
await ruleFormRef.value.validate();
return;
}
// if (!form.value.columnsVip) {
// ElMessage.error('请选择VIP栏目');
// tabIndex.value = 2;
// await ruleFormRef.value.validate();
// return;
// }
// if (!form.value.industrySelect) {
// ElMessage.error('请选择分行业类');
// tabIndex.value = 2;
// await ruleFormRef.value.validate();
// return;
// }
// if (form.value.column.earlyKnow.show && !form.value.summary) {
// ElMessage.success('选择展示在早知道栏目需要填写摘要');
// return;
// }
console.log('🚀 ~ submit ~ form.value:', form.value);
var tags = [];
if (form.value.tagSourceSelect) {
tagSourceList.value.forEach((item, index) => {
if (item.id == form.value.tagSourceSelect) {
tags.push(item);
}
});
}
if (form.value.tagDiySelect) {
form.value.tagDiySelect.forEach((item, index) => {
tagDiyList.value.forEach((childItem, childIndex) => {
if (item == childItem.id) {
tags.push(childItem);
}
});
});
}
let vip = {
id: form.value.columnsVipChild ? form.value.columnsVipChild : form.value.columnsVip,
type: form.value.showTypeVip,
};
let par = {
...form.value,
tag: {
source: form.value.tagSourceSelect,
fieldArr: form.value.tagDiySelect,
},
industries: form.value.industrySelect,
};
if (type == 0) {
let str = "请确认已审核该篇资讯,发布后前台将展示本资讯"
if (Session.get('userInfoLocal').userType == '00') {
str = '确认初审完成并提交复核?送审后不支持再次编辑';
if (props.data.status == 3) {
str = '确认撤销该篇资讯审核?';
} else {
str = '确认初审完成并提交复核?送审后不支持再次编辑';
}
} else if (Session.get('userInfoLocal').userType == '01') {
str = '请确认已审核该篇资讯,发布后前台将展示本资讯';
}
ElMessageBox.confirm(str, '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning',
})
.then(async () => {
// 发布
let { code, data } = await doNewsCreatePublish(par);
if (code == 200) {
ElMessage.success('操作成功');
goBack();
}
})
.catch(() => { });
} else if (type == 1) {
// 保存
let { code, data } = await doNewsSave(par);
if (code == 200) {
ElMessage.success('操作成功');
if (doNotBack) {
} else {
goBack();
}
}
}
}
const tabIndex = ref(0);
function stepChange(index: number) {
tabIndex.value = index;
}
function goBack() {
model.value = false;
emit('getData');
}
const infoData = ref({});
// 获取新闻详情
async function getInfo() {
console.log('🚀 ~ getInfo ~ route:', route);
let { code, data } = await getNewsDetail({ id: props.data.id });
if (code == 200) {
infoData.value = data;
form.value = data;
if (form.value.deleted) {
emit('handleEditStatus', true);
}
// 如果返回的栏目为空,填上默认字段
if (!form.value.column) {
form.value.column = {
vip: null,
everything: null,
};
}
// 如果返回的栏目为空(早知道),填上默认字段
if (!form.value.column?.earlyKnow) {
form.value.column.earlyKnow = {
show: false,
};
}
form.value.columnsVip = data.column?.vip?.id;
// 媒体来源
form.value.tagSourceSelect = data.tag.source?.id;
// 付费类型,目前这个字段灭用
form.value.type = 0;
// 初始化上传的封面
if (form.value.picture) {
pictureTemp.value = [
{
url: form.value.picture,
},
];
}
// 初始化标题字数
titleTextNum.value = form.value.title.length;
// VIP展示方式
form.value.showTypeVip = data.column.vip?.type;
// 初始化概念标签(多选)
form.value.tagDiySelect = [];
data.tag?.fieldArr?.forEach((item) => {
form.value.tagDiySelect.push(item.id);
});
// 初始化行业分类(多选)
form.value.industrySelect = [];
data.industry.forEach((item) => {
form.value.industrySelect.push(item.id);
});
// 如果频道标签有子标签
if (data.column?.vip?.child) {
vipChange(data.column.vip.id);
form.value.columnsVipChild = data.column.vip.child.id;
}
// 初始化天下事字段
if (!form.value.column.everything) {
form.value.column.everything = {
type: null,
};
}
// if (form.value.showTypeVip == null) {
// form.value.showTypeVip = -1;
// }
// if (form.value.column?.everything?.type == null) {
// form.value.column.everything.type = -1;
// }
form.value.content = form.value.content.replace(/\n{3,}/g, '\n');
}
}
const isShowVipChild = ref(false);
const vipChildList = ref([]);
function vipChange(val) {
let selectItem = {};
columnListVIp.value.forEach((item, index) => {
if (item.id == val) {
selectItem = item;
}
});
// 如果有二级栏目
if (selectItem.children && selectItem.children.length > 0) {
isShowVipChild.value = true;
vipChildList.value = selectItem.children;
form.value.columnsVipChild = vipChildList.value[0].id;
} else {
isShowVipChild.value = false;
form.value.columnsVipChild = null;
}
}
// 页面加载时
onMounted(async () => {
console.log('🚀 ~ file: index.vue:13 ~ onMounted ~ onMounted:');
NextLoading.done();
await getColumnVIPFn();
//如果是编辑进来
if (props.type == 1) {
getInfo();
}
// 自定义标签列表
getTagDiyFn();
// 来源标签列表
getTagSourceFn();
// 栏目列表
// getColumnFn();
// 行业分类列表
getTndustryFn();
});
watch(
() => props.data,
(newVal, oldVal) => {
getInfo();
}
);
function handleEditStatus(val) {
emit('handleEditStatus', val);
}
function doNewsPublishFn(item, status) {
emit('doNewsPublishFn', item, status);
}
function doDeleteNewsFn(item) {
emit('doDeleteNewsFn', item);
}
// 放大
const isFull = ref(false);
function clickFull() {
isFull.value = !isFull.value;
}
async function doApprovalFn() {
let str = '确认初审完成并提交复核?送审后不支持再次编辑';
if (props.data.status == 3) {
str = '确认撤销该篇资讯审核?';
} else {
str = '确认初审完成并提交复核?送审后不支持再次编辑';
}
ElMessageBox.confirm(str, '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning',
})
.then(async () => {
let { code } = props.data.status == 3 || props.data.status == 4 ? await doNewRevoke({
id: props.data.id,
}) : await doNewSubmit({
id: props.data.id,
});
if (code == 200) {
ElMessage.success('操作成功');
goBack();
}
})
.catch(() => { });
}
</script>
<style scoped lang="scss">
.drawer-container-mobile {
:deep(.modal-class) {
width: 100%;
inset: 0 0 0 auto !important;
transition: all 0.3s ease-in-out;
}
}
.drawer-container {
:deep(.modal-class) {
width: calc(100% - 560px);
inset: 0 0 0 auto !important;
transition: all 0.3s ease-in-out;
}
}
.drawer-container-100 {
:deep(.modal-class) {
width: calc(100% - 220px);
inset: 0 0 0 auto !important;
}
}
.step_bk {
padding: 20px 30px;
border-bottom: 1px solid #eee;
}
.drawer-header {
display: flex;
justify-content: space-between;
align-items: center;
padding-right: 20px;
.btn {
display: flex;
align-items: center;
}
}
</style>