粒子研究院后台前端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

586 lines
18 KiB

<template>
<div class="page">
<p class="page-name mb">文章详情</p>
<el-form :model="form" :rules="rules" class="input-form model" label-width="140px">
<el-form-item prop="title" label="标题">
<el-input
placeholder="请输入标题"
v-model.trim="form.title"
clearable
maxlength="15"
class="inline-input"
@change="nameChange"
></el-input>
</el-form-item>
<div class="item-line">
<el-form-item prop="columnId" label="所属栏目">
<el-cascader
ref="column"
v-model="form.columnId"
:options="columns"
:props="columnProps"
clearable></el-cascader>
</el-form-item>
<el-form-item prop="releaseTime" label="发布日期">
<el-date-picker
v-model="form.releaseTime"
type="date"
placeholder="选择日期"
format="yyyy-MM-dd"
value-format="yyyy-MM-dd">
</el-date-picker>
</el-form-item>
</div>
<div class="item-line">
<el-form-item prop="source" label="来源">
<el-input
placeholder="请输入来源"
v-model.trim="form.source"
clearable
maxlength="15"
class="inline-input"
@change="nameChange"
></el-input>
</el-form-item>
<el-form-item prop="author" label="作者">
<el-input
placeholder="请输入作者"
v-model.trim="form.author"
clearable
maxlength="15"
class="inline-input"
@change="nameChange"
></el-input>
</el-form-item>
</div>
<el-form-item prop="summary" label="摘要">
<el-input
type="textarea"
v-model.trim="form.summary"
clearable
></el-input>
</el-form-item>
<el-form-item prop="titleImg" label="封面图">
<el-upload
class="avatar-uploader"
accept=".jpg,.png,.jpeg,.gif"
:before-upload="beforeUpload"
:on-error="uploadError"
:on-success="uploadSuccess"
:show-file-list="false"
:action="this.api.upload"
:data="{
quote: form.title,
site: site.siteName,
uploader: userName
}"
>
<img v-if="form.titleImg" :src="form.titleImg" class="avatar">
<div class="uploader-default" v-else>
<img class="plus" src="@/assets/img/plus.png" alt="">
<p>点击上传</p>
</div>
</el-upload>
</el-form-item>
<el-form-item prop="bannerImg" label="Banner图" style="flex: 1;">
<el-upload
class="avatar-uploader avatar-uploader-lg"
accept=".jpg,.png,.jpeg,.gif"
:before-upload="beforeUpload"
:on-error="uploadError"
:on-success="uploadSuccessBanner"
:show-file-list="false"
:action="this.api.upload"
:data="{
quote: form.title,
site: site.siteName,
uploader: userName
}"
>
<img v-if="form.bannerImg" :src="form.bannerImg" class="avatar-lg">
<div class="uploader-default" v-else>
<img class="plus" src="@/assets/img/plus.png" alt="">
<p>点击上传</p>
</div>
</el-upload>
</el-form-item>
<el-form-item class="lg" prop="articleTemplate" label="独立文章模板">
<el-popover
placement="top-start"
trigger="hover"
content="默认使用栏目中设置的文章样式,如果需要为该篇文章指定专门的模板样式,可以设置此项">
<img slot="reference" class="info" src="@/assets/img/ques.png" alt="">
</el-popover>
<el-switch
v-model="form.templateStatus"
:active-value="1"
:inactive-value="0">
</el-switch>
<ul v-if="form.templateStatus" class="styles">
<template v-for="(item, i) in detailStyle">
<li v-if="item.id !== column.detailStyle" :key="i" @click="form.articleTemplate = item.id">
<div class="review">
<img :src="require('@/assets/img/article' + item.id + '.png')" alt="">
</div>
<el-radio v-model="form.articleTemplate" :label="item.id">{{ item.name }}</el-radio>
</li>
</template>
</ul>
</el-form-item>
<template v-if="!form.templateStatus || (form.templateStatus && form.articleTemplate === 2)">
<el-form-item prop="mainBody" label="正文">
<Editor api-key='rnk6zw9v267xqz7pf98twt1vmrvltmd436je7a642pckltda' v-model="form.mainBody" :init="editorConfig" />
</el-form-item>
<el-form-item prop="file" label="文件上传">
<el-upload
:on-remove="handleRemove"
:on-error="uploadError"
:on-success="uploadSuccessFile"
:limit="1"
:on-exceed="handleExceed"
:action="this.api.upload"
:file-list="fileList"
:data="{
quote: form.title,
site: site.siteName,
uploader: userName
}"
>
<el-button>上传</el-button>
</el-upload>
</el-form-item>
</template>
<template v-if="form.articleTemplate === 3">
<el-form-item prop="connectionType" label="连接类型">
<el-radio-group v-model="form.connectionType">
<el-radio :label="1">站内链接</el-radio>
<el-radio :label="2">站外链接</el-radio>
<el-radio :label="3">其他站点链接</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-show="form.connectionType === 1" prop="connectionType" label="站内链接">
<el-cascader
v-model="links"
:options="columns"
:props="columnProps"
clearable></el-cascader>
</el-form-item>
<el-form-item v-show="form.connectionType === 2" prop="connectionType" label="站内链接">
<el-input
placeholder="请输入站外链接"
v-model.trim="form.linkAddress"
clearable
></el-input>
</el-form-item>
<template v-if="form.connectionType === 3">
<el-form-item prop="siteSelection" label="站点选择">
<el-select v-model="form.siteSelection">
<el-option
v-for="item in sites"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="栏目">
<el-cascader
v-model="links"
:options="columns"
:props="columnProps"
clearable></el-cascader>
</el-form-item>
</template>
</template>
<el-form-item v-show="form.typeId === 4" prop="showWithDetails" label="栏目">
<el-switch
v-model="form.showWithDetails"
:active-value="1"
:inactive-value="0">
</el-switch>
</el-form-item>
</el-form>
<div class="btns">
<el-button type="primary" @click="submit(1)">发布</el-button>
<el-button @click="preview">预览</el-button>
<el-button @click="submit(0)">保存草稿</el-button>
<el-button @click="$router.push('/article')">取消</el-button>
</div>
</div>
</template>
<script>
import util from '@/libs/util'
import ColumnConst from '@/const/column'
import { mapState } from 'vuex'
import Editor from '@tinymce/tinymce-vue'
import editorConfig from './editor'
export default {
data() {
return {
site: this.$store.state.content.site,
nameRepeat: false,
types: ColumnConst.types,
templates: ColumnConst.templates,
sites: ColumnConst.sites,
detailStyle: ColumnConst.detailStyle,
columns: [],
columnProps: {
checkStrictly: true,
value: 'id',
label: 'columnName'
},
links: [],
form: {
siteId: this.$store.state.content.site.id,
id: this.$route.query.id || '',
founderId: this.$store.state.user.userId,
editorId: this.$store.state.user.userId,
templateStatus: 0,
articleTemplate: '',
author: '',
bannerImg: '',
columnId: +this.$route.query.columnId,
file: '',
isRelease: 0,
mainBody: '',
releaseTime: '',
source: '',
summary : '',
title: '',
titleImg: '',
connectionType : 1,
linkAddress: '',
siteSelection: 1,
},
rules: {
title: [
{ required: true, message: '请输入标题', trigger: 'blur' }
],
columnId: [
{ required: true, message: '请选择所属栏目', trigger: 'change' }
],
releaseTime: [
{ required: true, message: '请选择发布日期', trigger: 'change' }
],
mainBody: [
{ required: true, message: '请输入正文', trigger: 'blur' }
],
connectionType: [
{ required: true, message: '请选择连接类型', trigger: 'blur' }
],
},
fileList: [],
editorConfig,
submiting: false, // 新增编辑防抖标识
updateTime: 0
};
},
computed: {
...mapState('user', [
'userName'
]),
...mapState('content', [
'column'
])
},
components: {
Editor
},
watch: {
// 监听信息是否有更改,有的话页面离开的时候要询问是否要保存
form: {
handler(val){
this.updateTime++
},
deep:true
}
},
// 页面离开的时候如果没有保存则提示
beforeRouteLeave(to, from, next) {
if (this.submiting) {
next()
} else {
const { updateTime } = this
// 更改了信息才需要提示
if (updateTime > 2) {
this.$confirm(`所填写内容暂未保存,是否保存?`, '提示', {
type: 'warning'
}).then(() => {
this.submit(this.form.isRelease, next)
}).catch(() => {
next()
})
} else {
next()
}
}
},
mounted() {
this.$store.commit('user/setCrumbs', [
{
name: '站点管理',
route: '/site'
},
{
name: '内容管理'
},
{
name: '文章管理',
route: '/article'
},
{
name: this.$route.query.id ? '编辑' : '新增'
}
])
this.getList()
this.form.id && this.getData()
},
methods: {
// 获取栏目
getList() {
this.$post(this.api.listWithTree, {
siteId: this.site.id,
columnName: '',
templateId: '',
typeId : '',
isSort: 0
}).then(({ data }) => {
this.columns = data
let { columnId } = this.$route.query
// 如果是新增文章,则要默认选中栏目,因为从外面带进来的是单个id,要取到父id来选中到里面的层级
if (columnId && data.length) {
columnId = +columnId
let ids = []
// 递归获取完整id
const getId = (list, parentId) => {
for (const i in list) {
const e = list[i]
if (e.id === columnId) {
ids = [...parentId, list[i].id]
break
} else {
getId(e.children, [...parentId, e.id])
}
}
}
getId(data, [])
if (!ids.length) ids = [data[0].id] // 如果因为切换站点而没有匹配的栏目id,则取第一个栏目
this.form.columnId = ids
}
}).catch(err => {})
},
// 每个层级加上父级id的集合
getId(list, ids) {
list.forEach(e => {
e.ids = ids ? [...ids, e.id] : [e.id]
e.children.length ? this.getId(e.children, e.ids) : delete e.children
})
},
// 获取详情
getData() {
this.$post(`${this.api.findArticle}?id=${this.form.id}`).then(({ data }) => {
this.form = data
if (data.articleTemplate === 3 && data.connectionType !== 2 && data.linkAddress) this.links = data.linkAddress.split(',').map(e => +e)
this.originalName = data.title
const { file } = data
if (file) this.fileList = [{name: file, url: file}] // 文件上传回显
}).catch(err => {})
},
// 文章名称判重
nameChange(){
const { title, level, id } = this.form
if(title && title !== this.originalName){
this.$post(this.api.checkIfTheTitleIsRepeat, {
siteId: this.site.id,
title,
id: id || ''
}).then(res => {
this.nameRepeat = false
}).catch(res => {
this.nameRepeat = true
})
}else{
this.nameRepeat = false
}
},
// 导入前的钩子
beforeUpload(file) {
const { size, name } = file
const ext = name.substring(name.lastIndexOf('.') + 1)
if (!util.isImg(ext)) {
this.$message.error('请上传图片!')
return false
}
if (size / 1024 / 1024 > 1) {
this.$message.error('请上传1M以内的图片!')
return false
}
},
uploadError(err, file, fileList) {
this.$message({
message: "上传出错,请重试!",
type: "error",
center: true
})
},
beforeRemove(file, fileList) {
return this.$confirm(`确定移除 ${file.name}`);
},
handleExceed(files, fileList) {
util.errorMsg(`当前限制选择 1 个文件,如需更换,请删除上一个文件再重新选择!`);
},
handleRemove(file, fileList) {
this.form.file = ''
},
uploadSuccess(res) {
let url = this.form.titleImg
url && this.$del(this.api.delFile, [url.split('/').pop()]).then(res => {}).catch(e => {})
this.form.titleImg = res.url
},
uploadSuccessBanner(res) {
let url = this.form.bannerImg
url && this.$del(this.api.delFile, [url.split('/').pop()]).then(res => {}).catch(e => {})
this.form.bannerImg = res.url
},
uploadSuccessFile(res) {
this.form.file = res.url
},
// 预览
preview() {
},
// 提交
submit(isRelease, next) {
if (this.submiting) return false
const { form } = this
if (!form.title) return util.errorMsg('请填写标题')
if (this.nameRepeat) return util.errorMsg('该标题已重复!')
if (!form.releaseTime && isRelease) return util.errorMsg('请选择发布日期')
if (typeof form.fatherId === 'object') form.fatherId = form.fatherId[form.fatherId.length - 1]
if (form.articleTemplate === 3 && form.connectionType !== 2) {
const { links } = this
if (!links.length && form.connectionType === 1 && isRelease) return util.errorMsg('请选择站内链接')
if (!links.length && form.connectionType === 3 && isRelease) return util.errorMsg('请选择栏目')
form.linkAddress = links.join()
}
if (((form.templateStatus && form.articleTemplate === 2) || !form.templateStatus) && !form.mainBody && isRelease) return util.errorMsg('请输入正文')
const { columnId } = form
if (typeof columnId === 'object') form.columnId = columnId[columnId.length - 1]
form.isRelease = isRelease
this.submiting = true
if (form.id) {
delete form.children
form.editorId = +this.$store.state.user.userId
this.$post(this.api.updateArticle, form).then(res => {
util.successMsg('修改成功')
next ? next() : this.$router.back()
}).catch(err => {
this.submiting = false
})
} else {
this.$post(this.api.saveArticle, form).then(res => {
util.successMsg('创建成功')
next ? next() : this.$router.back()
}).catch(err => {
this.submiting = false
})
}
}
}
};
</script>
<style lang="scss" scoped>
$upload-width: 220px;
$upload-height: 102px;
$upload-lg-height: 102px;
/deep/ .avatar-uploader {
.el-upload {
position: relative;
width: $upload-width;
height: $upload-height;
border: 1px solid #DCDEE0;
border-radius: 2px;
cursor: pointer;
overflow: hidden;
.uploader-default {
display: flex;
height: $upload-height;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
background: #FAFAFA;
p {
margin-top: 10px;
font-size: 14px;
color: #333;
line-height: 20px;
}
}
}
&.avatar-uploader-lg {
.el-upload {
width: 100%;
max-width: 820px;
height: $upload-lg-height;
.uploader-default {
height: $upload-lg-height;
}
}
}
.avatar {
display: block;
width: $upload-width;
height: $upload-height;
}
.avatar-lg {
display: block;
width: 100%;
height: $upload-lg-height;
}
.el-upload__tip {
margin-top: 0;
p {
font-size: 12px;
color: #333;
}
}
}
.style-wrap {
display: flex;
margin-top: 10px;
.label {
margin-right: 30px;
}
}
.styles {
display: flex;
margin-top: 20px;
li {
margin-right: 20px;
text-align: center;
cursor: pointer;
&:hover .review {
border-color: #2962FF;
}
}
.review {
display: flex;
justify-content: center;
align-items: center;
width: 170px;
height: 112px;
margin-bottom: 10px;
border: 1px solid #DCDEE0;
border-radius: 2px;
}
}
.info {
position: absolute;
top: 8px;
left: -32px;
cursor: pointer;
}
</style>