parent
a6a1a54449
commit
9c208766b9
15 changed files with 3674 additions and 5 deletions
After Width: | Height: | Size: 287 B |
@ -0,0 +1,235 @@ |
||||
<template> |
||||
<div> |
||||
<div class="cropper-content"> |
||||
<!-- 剪裁框 --> |
||||
<div class="cropper"> |
||||
<vueCropper |
||||
ref="cropper" |
||||
:img="option.img" |
||||
:output-size="option.size" |
||||
:output-type="option.outputType" |
||||
:info="true" |
||||
:full="option.full" |
||||
:can-move="option.canMove" |
||||
:can-move-box="option.canMoveBox" |
||||
:original="option.original" |
||||
:auto-crop="option.autoCrop" |
||||
:auto-crop-width="option.autoCropWidth" |
||||
:auto-crop-height="option.autoCropHeight" |
||||
:fixed-box="option.fixedBox" |
||||
:fixed="fixed" |
||||
:fixed-number="fixedNumber" |
||||
@realTime="realTime" /> |
||||
<!-- <vueCropper ref="cropper" :img="option.img" :outputSize="option.size" :outputType="option.outputType"></vueCropper> --> |
||||
</div> |
||||
<!-- 预览框 --> |
||||
<div |
||||
class="show-preview" |
||||
:style="{'width': '500px', 'height': '400px', 'overflow': 'hidden', 'margin': '0 25px', 'display':'flex', 'align-items' : 'center'}"> |
||||
<div :style="previews.div" class="preview"> |
||||
<img :src="previews.url" :style="previews.img" /> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<div class="footer-btn"> |
||||
<!-- 缩放旋转按钮 --> |
||||
<!-- <div class="scope-btn"> |
||||
<el-button type="primary" icon="el-icon-zoom-in" @click="changeScale(1)"></el-button> |
||||
<el-button type="primary" icon="el-icon-zoom-out" @click="changeScale(-1)"></el-button> |
||||
<el-button type="primary" @click="rotateLeft">逆时针旋转</el-button> |
||||
<el-button type="primary" @click="rotateRight">顺时针旋转</el-button> |
||||
</div>--> |
||||
<!-- 确认上传按钮 --> |
||||
<div class="upload-btn"> |
||||
<el-button |
||||
type="primary" |
||||
:loading="isUpload" |
||||
:disabled="isDisabled" |
||||
@click.prevent="uploadImg('blob')"> |
||||
上传 |
||||
</el-button> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
import { |
||||
VueCropper |
||||
} from 'vue-cropper' |
||||
import {compress, compressAccurately} from 'image-conversion' |
||||
export default { |
||||
components: { |
||||
VueCropper |
||||
}, |
||||
props: { |
||||
// 上传状态 |
||||
isUpload: { |
||||
type: Boolean, |
||||
default: false |
||||
}, |
||||
// 图片对象 |
||||
imgFile: { |
||||
type: Object, |
||||
require: true, |
||||
default: () => { |
||||
return { url: '', size: 10 } |
||||
} |
||||
}, |
||||
// 截图框比例 |
||||
fixedNumber: { |
||||
type: Array, |
||||
default: () => { |
||||
return [1, 0.26] |
||||
} |
||||
}, |
||||
fixed: { |
||||
type: Boolean, |
||||
default: true |
||||
} |
||||
}, |
||||
data() { |
||||
return { |
||||
previews: {}, // 预览数据 |
||||
option: { |
||||
img: '', // 裁剪图片的地址 (默认:空) |
||||
size: 0.8, // 裁剪生成图片的质量 (默认:1) |
||||
full: true, // 是否输出原图比例的截图 选true生成的图片会非常大 (默认:false) |
||||
outputType: 'jpg', // 裁剪生成图片的格式 (默认:jpg) |
||||
canMove: true, // 上传图片是否可以移动 (默认:true) |
||||
original: false, // 上传图片按照原始比例渲染 (默认:false) |
||||
canMoveBox: true, // 截图框能否拖动 (默认:true) |
||||
autoCrop: true, // 是否默认生成截图框 (默认:false) |
||||
autoCropWidth: 480, // 默认生成截图框宽度 (默认:80%) |
||||
autoCropHeight: 124, // 默认生成截图框高度 (默认:80%) |
||||
fixedBox: false, // 固定截图框大小 不允许改变 (默认:false) |
||||
fixed: true, // 是否开启截图框宽高固定比例 (默认:true) |
||||
fixedNumber: [1, 0.26], // 截图框比例 (默认:[1:1]) |
||||
enlarge: 1 |
||||
}, |
||||
isDisabled: false |
||||
} |
||||
}, |
||||
methods: { |
||||
changeScale(num) { |
||||
// 图片缩放 |
||||
num = num || 1 |
||||
this.$refs.cropper.changeScale(num) |
||||
}, |
||||
rotateLeft() { |
||||
// 向左旋转 |
||||
this.$refs.cropper.rotateLeft() |
||||
}, |
||||
rotateRight() { |
||||
// 向右旋转 |
||||
this.$refs.cropper.rotateRight() |
||||
}, |
||||
updateImg(file) { |
||||
this.option.img = file.url |
||||
this.option.size = file.size / 1024 > 200 ? 0.9 : 0.95 |
||||
}, |
||||
realTime(data) { |
||||
// 实时预览 |
||||
this.previews = data |
||||
}, |
||||
close() { |
||||
}, |
||||
uploadImg(type) { |
||||
this.isDisabled = true |
||||
// 将剪裁好的图片回传给父组件 |
||||
const that = this |
||||
if (type === 'blob') { |
||||
this.$refs.cropper.getCropBlob(data => { |
||||
compress(data, 0.8).then(res => { |
||||
that.$emit('upload', res) |
||||
}) |
||||
}) |
||||
} else { |
||||
this.$refs.cropper.getCropData(data => { |
||||
that.$emit('upload', data) |
||||
}) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
<style lang="scss" scoped> |
||||
.cropper-content { |
||||
display: flex; |
||||
display: -webkit-flex; |
||||
justify-content: flex-end; |
||||
-webkit-justify-content: flex-end; |
||||
} |
||||
|
||||
.cropper-content .cropper { |
||||
width: 500px; |
||||
height: 400px; |
||||
} |
||||
|
||||
.cropper-content .show-preview { |
||||
flex: 1; |
||||
-webkit-flex: 1; |
||||
display: flex; |
||||
display: -webkit-flex; |
||||
justify-content: center; |
||||
-webkit-justify-content: center; |
||||
overflow: hidden; |
||||
border: 1px solid #cccccc; |
||||
background: #cccccc; |
||||
margin-left: 40px; |
||||
} |
||||
|
||||
.preview { |
||||
overflow: hidden; |
||||
border: 1px solid #cccccc; |
||||
background: #cccccc; |
||||
} |
||||
|
||||
.footer-btn { |
||||
margin-top: 30px; |
||||
display: flex; |
||||
display: -webkit-flex; |
||||
justify-content: flex-end; |
||||
-webkit-justify-content: flex-end; |
||||
} |
||||
|
||||
.footer-btn .scope-btn { |
||||
width: 500px; |
||||
display: flex; |
||||
display: -webkit-flex; |
||||
justify-content: space-between; |
||||
-webkit-justify-content: space-between; |
||||
} |
||||
|
||||
.footer-btn .upload-btn { |
||||
flex: 1; |
||||
-webkit-flex: 1; |
||||
display: flex; |
||||
display: -webkit-flex; |
||||
justify-content: center; |
||||
-webkit-justify-content: center; |
||||
} |
||||
|
||||
.footer-btn .btn { |
||||
outline: none; |
||||
display: inline-block; |
||||
line-height: 1; |
||||
white-space: nowrap; |
||||
cursor: pointer; |
||||
-webkit-appearance: none; |
||||
text-align: center; |
||||
-webkit-box-sizing: border-box; |
||||
box-sizing: border-box; |
||||
outline: 0; |
||||
margin: 0; |
||||
-webkit-transition: 0.1s; |
||||
transition: 0.1s; |
||||
font-weight: 500; |
||||
padding: 8px 15px; |
||||
font-size: 12px; |
||||
border-radius: 3px; |
||||
color: #fff; |
||||
background-color: #67c23a; |
||||
border-color: #67c23a; |
||||
} |
||||
</style> |
@ -0,0 +1,535 @@ |
||||
<template> |
||||
<div> |
||||
<!-- 多图片上传 --> |
||||
<el-upload |
||||
ref="upload" |
||||
drag |
||||
action="string" |
||||
:list-type="listType" |
||||
accept="image/*" |
||||
:on-preview="handlePreview" |
||||
:auto-upload="false" |
||||
:on-change="handleChange" |
||||
:file-list="uploadList" |
||||
class="img-upload clearfix" |
||||
:class="{ 'max-num': !isShowPlus || isPreview, describes: describe }"> |
||||
<i class="el-icon-plus"></i> |
||||
<div class="el-upload__text"> |
||||
<slot name="el-upload__text"></slot> |
||||
</div> |
||||
<div v-if="describe" slot="tip" class="el-upload__tip"> |
||||
{{ describe }} |
||||
</div> |
||||
<div slot="file" slot-scope="{ scope }" class="upload-item-container"> |
||||
<img |
||||
class="el-upload-list__item-thumbnail" |
||||
:class="{ cover: isSingle && !isNeedChange }" |
||||
:src="scope.url" |
||||
alt |
||||
@click="handlePreview(scope)" /> |
||||
<div |
||||
v-if="!isSingle && !isPreview" |
||||
class="el-upload-list__item-handover"> |
||||
<i |
||||
class="el-icon-arrow-left" |
||||
:class="{ disabled: scope.prevDisabled }" |
||||
@click.stop="movePrev(scope)"></i> |
||||
<i |
||||
class="el-icon-arrow-right" |
||||
:class="{ disabled: scope.nextDisabled }" |
||||
@click.stop="moveNext(scope)"></i> |
||||
</div> |
||||
<div v-if="isSingle && !isPreview"> |
||||
<p v-if="isNeedChange" class="tac" @click="changeImg($event)"> |
||||
更 换 |
||||
</p> |
||||
</div> |
||||
<span |
||||
v-if="!isPreview" |
||||
class="el-upload-list__item-delete" |
||||
@click="handleRemove(scope)"> |
||||
<i class="el-icon-close"></i> |
||||
</span> |
||||
</div> |
||||
</el-upload> |
||||
<!-- 多图片预览弹窗 --> |
||||
<el-dialog |
||||
append-to-body |
||||
:visible.sync="dialogVisible" |
||||
class="img_view" |
||||
top="20vh" |
||||
width="560px"> |
||||
<!-- <span class="el-carousel__arrow el-carousel__arrow--left" @click="prevAction"> |
||||
<i class="el-icon-arrow-left"></i> |
||||
</span> |
||||
<span class="el-carousel__arrow el-carousel__arrow--right" @click="nextAction"> |
||||
<i class="el-icon-arrow-right"></i> |
||||
</span>--> |
||||
<el-carousel |
||||
v-if="dialogVisible" |
||||
ref="el_carousel" |
||||
height="420px" |
||||
:autoplay="false" |
||||
:class="[uploadList.length < 2 ? 'isShowCutBtn' : '']" |
||||
:initial-index="currentNum"> |
||||
<el-carousel-item v-for="(item, index) in uploadList" :key="index"> |
||||
<img :src="item.url" alt style="width:100%" /> |
||||
</el-carousel-item> |
||||
</el-carousel> |
||||
</el-dialog> |
||||
<!-- 剪裁组件弹窗 --> |
||||
<el-dialog append-to-body :visible.sync="cropperModel" width="1100px"> |
||||
<Cropper |
||||
ref="vueCropper" |
||||
:is-upload="isUpload" |
||||
:img-file="file" |
||||
:fixed-number="fixedNumber" |
||||
:fixed="fixed" |
||||
:fixed-box="fixedBox" |
||||
@upload="customUpload" /> |
||||
</el-dialog> |
||||
</div> |
||||
</template> |
||||
<script> |
||||
import Cropper from './Cropper' |
||||
export default { |
||||
name: 'Uploader', |
||||
components: { |
||||
Cropper |
||||
}, |
||||
props: { |
||||
// 上传api方法 |
||||
uploadMethodName: { |
||||
type: String, |
||||
default: '', |
||||
required: true |
||||
}, |
||||
// 最大图片数量 |
||||
maxImages: { |
||||
type: Number, |
||||
default: 9 |
||||
}, |
||||
// 是否单图 |
||||
isSingle: { |
||||
type: Boolean, |
||||
default: false |
||||
}, |
||||
// 单图模式是否显示更改按钮 |
||||
isNeedChange: { |
||||
type: Boolean, |
||||
default: false |
||||
}, |
||||
// 初始化filelist |
||||
initFileList: { |
||||
type: Array, |
||||
default: () => [] |
||||
}, |
||||
// 剪裁框比例设置 |
||||
fixedNumber: { |
||||
type: Array, |
||||
default: () => [4, 3] |
||||
}, |
||||
// 是否固定宽高比例 |
||||
fixed: { |
||||
type: Boolean, |
||||
default: true |
||||
}, |
||||
// 开启查看模式 |
||||
isPreview: { |
||||
type: Boolean, |
||||
default: false |
||||
}, |
||||
// 推荐上传描述 |
||||
describe: { |
||||
type: String, |
||||
default: '' |
||||
}, |
||||
// 是否固定截图框大小 不允许改变 |
||||
fixedBox: { |
||||
type: Boolean, |
||||
default: false |
||||
} |
||||
}, |
||||
data() { |
||||
return { |
||||
isUpload: false, |
||||
file: {}, // 当前被选择的图片文件 |
||||
// dialogImageUrl: '', // 弹窗内图片链接 |
||||
uploadList: [], // 上传图片列表 |
||||
dialogVisible: false, // 展示弹窗开关 |
||||
cropperModel: false, // 剪裁组件弹窗开关 |
||||
currentNum: 0 // 当前点击的是第几张图片 |
||||
} |
||||
}, |
||||
computed: { |
||||
isShowPlus() { |
||||
if (this.isSingle && this.uploadList.length > 0) { |
||||
return false |
||||
} |
||||
if (!this.isSingle && this.uploadList.length >= this.maxImages) { |
||||
return false |
||||
} |
||||
return true |
||||
}, |
||||
listType() { |
||||
return 'picture-card' |
||||
} |
||||
}, |
||||
watch: { |
||||
uploadList(newVal) { |
||||
if (!newVal.length) { |
||||
return |
||||
} |
||||
this.uploadList.map((item, index) => { |
||||
item.prevDisabled = index === 0 |
||||
item.nextDisabled = index === this.uploadList.length - 1 |
||||
}) |
||||
this.$emit('imgupload', newVal) |
||||
}, |
||||
initFileList(newVal) { |
||||
this.updateList(newVal) |
||||
} |
||||
}, |
||||
mounted() { |
||||
this.updateList(this.initFileList) |
||||
}, |
||||
methods: { |
||||
handlePreview(file) { |
||||
// 点击进行图片展示 |
||||
this.currentNum = this.uploadList.findIndex( |
||||
item => item.uid === file.uid |
||||
) |
||||
console.log('file--', file, this.currentNum) |
||||
// this.dialogImageUrl = file.url; |
||||
|
||||
this.dialogVisible = true |
||||
}, |
||||
// 切换图片 |
||||
prevAction() { |
||||
this.$refs.el_carousel.prev() |
||||
}, |
||||
nextAction() { |
||||
this.$refs.el_carousel.next() |
||||
}, |
||||
handleRemove(file) { |
||||
const index = this.uploadList.findIndex(item => item.uid === file.uid) |
||||
this.uploadList.splice(index, 1) |
||||
this.$emit('imgupload', this.uploadList) |
||||
console.log('查看删除文件', file, this.uploadList) |
||||
}, |
||||
handleChange(file, fileList) { |
||||
// var fileSize = file.size / 1024 > 300 |
||||
// if (fileSize) { |
||||
// this.$message.info('图片大小不能超过300k'); |
||||
// return |
||||
// } |
||||
this.file = file |
||||
this.uploadList = this.uploadList.filter( |
||||
item => item.status === 'success' |
||||
) |
||||
console.log(fileList, this.uploadList) |
||||
// 弹出剪裁框,将当前文件设置为文件 |
||||
this.cropperModel = true |
||||
this.$nextTick(() => { |
||||
if (this.$refs.vueCropper) { |
||||
this.$refs.vueCropper.isDisabled = false |
||||
this.$refs.vueCropper.updateImg() |
||||
} |
||||
}) |
||||
}, |
||||
movePrev(file) { |
||||
if (file.prevDisabled) { |
||||
return |
||||
} |
||||
const index = this.uploadList.findIndex(item => item.uid === file.uid) |
||||
this.swapArray(this.uploadList, index, index - 1) |
||||
}, |
||||
moveNext(file) { |
||||
if (file.nextDisabled) { |
||||
return |
||||
} |
||||
const index = this.uploadList.findIndex(item => item.uid === file.uid) |
||||
this.swapArray(this.uploadList, index, index + 1) |
||||
}, |
||||
swapArray(arr, index1, index2) { |
||||
arr[index1] = arr.splice(index2, 1, arr[index1])[0] |
||||
return arr |
||||
}, |
||||
changeImg($e) { |
||||
console.log($e) |
||||
}, |
||||
customUpload(data) { |
||||
// 自定义upload事件 |
||||
// console.log(data); |
||||
// let _data = this.compress(img); |
||||
const blob = this.dataURItoBlob(data) |
||||
const formData = new FormData() |
||||
formData.append('file', blob, this.file.name) // 有的后台需要传文件名,不然会报错 |
||||
this.imgUpload(formData) |
||||
}, |
||||
async imgUpload(formData) { |
||||
this.isUpload = true |
||||
await this.$api[this.uploadMethodName]({ |
||||
data: formData, |
||||
showLoading: false |
||||
}) |
||||
.then(res => { |
||||
// 上传成功将照片传回父组件 |
||||
console.log(this.uploadList) |
||||
this.uploadList = this.isSingle ? res : this.uploadList.concat(res) |
||||
this.uploadList.forEach(item => { |
||||
item.name = item.fileId |
||||
item.url = `/common-service/file/downloadFileFromOSS?key=${item.fileId}` |
||||
}) |
||||
}) |
||||
.catch(() => { |
||||
this.$refs.vueCropper.isDisabled = false |
||||
}) |
||||
this.isUpload = false |
||||
this.cropperModel = false |
||||
}, |
||||
formatImgArr(arr) { |
||||
const result = arr.map((item, index) => { |
||||
if (typeof item === 'string') { |
||||
return { |
||||
url: item, |
||||
uid: `index${index}` |
||||
} |
||||
} |
||||
return item.url |
||||
|
||||
}) |
||||
return result |
||||
}, |
||||
// 压缩图片 |
||||
compress(img) { |
||||
const canvas = document.createElement('canvas') |
||||
const ctx = canvas.getContext('2d') |
||||
// let initSize = img.src.length; |
||||
const width = img.width |
||||
const height = img.height |
||||
canvas.width = width |
||||
canvas.height = height |
||||
// 铺底色 |
||||
ctx.fillStyle = '#fff' |
||||
ctx.fillRect(0, 0, canvas.width, canvas.height) |
||||
ctx.drawImage(img, 0, 0, width, height) |
||||
// 进行压缩 |
||||
const ndata = canvas.toDataURL('image/jpeg', 0.8) |
||||
return ndata |
||||
}, |
||||
// base64转成bolb对象 |
||||
dataURItoBlob(base64Data) { |
||||
let byteString |
||||
if (base64Data.split(',')[0].indexOf('base64') >= 0) { |
||||
byteString = atob(base64Data.split(',')[1]) |
||||
} else { |
||||
byteString = unescape(base64Data.split(',')[1]) |
||||
} |
||||
const mimeString = base64Data |
||||
.split(',')[0] |
||||
.split(':')[1] |
||||
.split(';')[0] |
||||
// const mimeString = 'image/jpeg' |
||||
console.log(mimeString, 'fsnajkcbnjkscsa---') |
||||
const ia = new Uint8Array(byteString.length) |
||||
for (let i = 0; i < byteString.length; i++) { |
||||
ia[i] = byteString.charCodeAt(i) |
||||
} |
||||
return new Blob([ia], { |
||||
type: mimeString |
||||
}) |
||||
}, |
||||
updateList(val) { |
||||
this.uploadList = this.$copy(val).map(item => ({ |
||||
...item, |
||||
businessId: item.businessId || null, |
||||
fileId: item.fileId || item, |
||||
name: item.fileId || item, |
||||
url: `/common-service/file/downloadFileFromOSS?key=${item.fileId || |
||||
item}` |
||||
})) |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
<style lang="scss"> |
||||
.img-upload { |
||||
// width: 840px; |
||||
margin-left: 20px; |
||||
text-align: left; |
||||
.el-upload--picture-card { |
||||
width: 120px; |
||||
height: 120px; |
||||
line-height: inherit; |
||||
} |
||||
&.max-num { |
||||
.el-upload { |
||||
display: none; |
||||
} |
||||
} |
||||
.el-upload { |
||||
border: 0; |
||||
.el-upload-dragger { |
||||
width: 120px; |
||||
height: 120px; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
background: #fafafa; |
||||
flex-direction: column; |
||||
.el-icon-plus { |
||||
font-size: 37px; |
||||
color: #ccc; |
||||
} |
||||
} |
||||
} |
||||
|
||||
.el-upload-list--picture-card { |
||||
.el-upload-list__item { |
||||
overflow: visible; |
||||
position: relative; |
||||
height: 120px; |
||||
width: 120px; |
||||
margin: 0 24px 32px 0; |
||||
// @include borderBase; |
||||
outline: 0; |
||||
} |
||||
|
||||
.upload-item-container { |
||||
display: flex; |
||||
height: 100%; |
||||
background: rgba(237, 237, 237, 0.28); |
||||
flex-direction: column; |
||||
} |
||||
|
||||
.el-upload-list__item-thumbnail { |
||||
border-radius: 5px; |
||||
height: 76%; |
||||
&.cover { |
||||
height: 100%; |
||||
} |
||||
} |
||||
p.tac { |
||||
line-height: 28px; |
||||
color: #5f5d5d; |
||||
cursor: pointer; |
||||
} |
||||
.el-upload-list__item-handover { |
||||
flex: 1; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: space-between; |
||||
padding: 0 20px; |
||||
|
||||
> i { |
||||
cursor: pointer; |
||||
&::before { |
||||
width: 16px; |
||||
height: 16px; |
||||
display: inline-block; |
||||
box-sizing: border-box; |
||||
border-radius: 50%; |
||||
border: 1px solid #5f5d5d; |
||||
font-size: 12px; |
||||
line-height: 16px; |
||||
text-align: center; |
||||
} |
||||
&.disabled { |
||||
&::before { |
||||
border: 1px solid #939393; |
||||
color: #939393; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
.el-upload-list__item-delete { |
||||
position: absolute; |
||||
right: -9px; |
||||
top: -9px; |
||||
display: block; |
||||
height: 24px; |
||||
width: 24px; |
||||
background-color: #ffffff; |
||||
border: 1px solid #d5341e; |
||||
border-radius: 50%; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
> i { |
||||
position: static; |
||||
font-size: 14px; |
||||
color: #d5341e; |
||||
display: block; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
.describes { |
||||
display: flex; |
||||
.el-upload__tip { |
||||
margin-left: 8px; |
||||
color: #939393; |
||||
} |
||||
} |
||||
.v-modal { |
||||
opacity: 0.3; |
||||
} |
||||
.img_view.el-dialog__wrapper { |
||||
.el-dialog { |
||||
background: none; |
||||
box-shadow: none; |
||||
} |
||||
.el-dialog__header { |
||||
display: none; |
||||
} |
||||
.el-dialog__body { |
||||
padding: 0; |
||||
} |
||||
.title { |
||||
display: flex; |
||||
justify-content: flex-end; |
||||
span { |
||||
line-height: 48px; |
||||
width: 80px; |
||||
height: 48px; |
||||
text-align: right; |
||||
cursor: pointer; |
||||
font-size: 14px; |
||||
color: #ffffff; |
||||
} |
||||
} |
||||
.el-carousel__indicators--horizontal { |
||||
display: none; |
||||
} |
||||
.el-carousel__arrow { |
||||
width: 40px; |
||||
height: 40px; |
||||
box-sizing: border-box; |
||||
color: #5f5d5d; |
||||
background: rgba(255, 255, 255, 0.5); |
||||
border: 1px solid #5f5d5d; |
||||
i { |
||||
&::before { |
||||
font-size: 28px; |
||||
line-height: 40px; |
||||
} |
||||
} |
||||
} |
||||
.el-carousel { |
||||
width: 100%; |
||||
} |
||||
.isShowCutBtn { |
||||
.el-carousel__arrow { |
||||
display: none; |
||||
} |
||||
} |
||||
.el-carousel__arrow.el-carousel__arrow--left { |
||||
left: 0; |
||||
} |
||||
.el-carousel__arrow.el-carousel__arrow--right { |
||||
right: 0; |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,69 @@ |
||||
<template> |
||||
<div class="page system" style="padding: 0"> |
||||
<div class="tabs"> |
||||
<a class="item" v-for="(item,index) in tabs" :key="index" :class="{active: index == active}" @click="tabChange(index)">{{ item }}</a> |
||||
</div> |
||||
|
||||
<staff v-if="active == 'staff'"></staff> |
||||
<pc-role v-if="active == 'pcRole'"></pc-role> |
||||
<mobile-role v-if="active == 'mobileRole'"></mobile-role> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
import Setting from "@/setting"; |
||||
import staff from "./staff"; |
||||
import pcRole from "./pcRole"; |
||||
import mobileRole from "./mobileRole"; |
||||
export default { |
||||
data() { |
||||
return { |
||||
active: this.$route.query.type || 'staff', |
||||
tabs: { |
||||
staff: "合伙人学习管理", |
||||
pcRole: "合伙人资讯管理", |
||||
mobileRole: "方案管理" |
||||
} |
||||
}; |
||||
}, |
||||
components: { |
||||
staff, |
||||
pcRole, |
||||
mobileRole |
||||
}, |
||||
created() { |
||||
Setting.dynamicRoute && this.initTabs(); |
||||
}, |
||||
methods: { |
||||
tabChange(index) { |
||||
this.active = index |
||||
this.$router.push({ |
||||
path: 'parnerOperation', |
||||
query: { |
||||
...this.$route.query, |
||||
type: index |
||||
} |
||||
}) |
||||
}, |
||||
initTabs() { |
||||
const btns = this.$store.state.btns |
||||
const tab1 = btns.includes('/parner:合伙人学习管理') |
||||
const tab2 = btns.includes('/parner:合伙人资讯管理') |
||||
const tab3 = btns.includes('/parner:方案管理') |
||||
|
||||
tab1 || delete this.tabs.staff |
||||
tab2 || delete this.tabs.pcRole |
||||
tab3 || delete this.tabs.mobileRole |
||||
const type = this.$route.query.type |
||||
const keys = Object.keys(this.tabs) |
||||
this.active = keys.includes(type) ? type : keys[0] |
||||
} |
||||
} |
||||
}; |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.system { |
||||
min-height: calc(100vh - 170px); |
||||
} |
||||
</style> |
@ -0,0 +1,967 @@ |
||||
<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 |
||||
id="articleTitle" |
||||
style="width: 940px" |
||||
placeholder="请输入标题" |
||||
v-model="form.title" |
||||
clearable |
||||
maxlength="100" |
||||
></el-input> |
||||
</el-form-item> |
||||
<div class="item-line"> |
||||
<el-form-item prop="releaseTime" label="发布日期"> |
||||
<el-date-picker |
||||
v-model="form.releaseTime" |
||||
type="date" |
||||
placeholder="选择日期" |
||||
format="yyyy-MM-dd" |
||||
:clearable="false" |
||||
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="50" |
||||
class="inline-input" |
||||
></el-input> |
||||
</el-form-item> |
||||
<el-form-item prop="author" label="作者"> |
||||
<el-input |
||||
v-model="form.author" |
||||
clearable |
||||
maxlength="50" |
||||
class="inline-input" |
||||
></el-input> |
||||
</el-form-item> |
||||
</div> |
||||
<div class="item-line"> |
||||
<el-form-item prop="edit" label="编辑"> |
||||
<el-input |
||||
placeholder="请输入编辑" |
||||
v-model.trim="form.edit" |
||||
clearable |
||||
maxlength="50" |
||||
class="inline-input" |
||||
></el-input> |
||||
</el-form-item> |
||||
<el-form-item prop="audit" label="审核"> |
||||
<el-input |
||||
placeholder="请输入审核" |
||||
v-model.trim="form.audit" |
||||
clearable |
||||
maxlength="50" |
||||
class="inline-input" |
||||
></el-input> |
||||
</el-form-item> |
||||
</div> |
||||
|
||||
<div class="item-line"> |
||||
<el-form-item prop="source" label="所属分类"> |
||||
<el-select style="width: 234px;" v-model="form.classificationId"> |
||||
<template v-for="item in classifications"> |
||||
<el-option |
||||
v-if="item.id" |
||||
:key="item.id" |
||||
:label="item.classificationName" |
||||
:value="item.id"> |
||||
</el-option> |
||||
</template> |
||||
</el-select> |
||||
<el-button class="set-btn" type="primary" @click="setClass">设置</el-button> |
||||
</el-form-item> |
||||
<el-form-item prop="author" label="主题标签"> |
||||
<el-select style="width: 234px;" v-model="form.lableId" multiple> |
||||
<template v-for="item in labels"> |
||||
<el-option |
||||
v-if="item.id" |
||||
:key="item.id" |
||||
:label="item.labelName" |
||||
:value="item.id"> |
||||
</el-option> |
||||
</template> |
||||
</el-select> |
||||
<el-button class="set-btn" type="primary" @click="setLabel">设置</el-button> |
||||
</el-form-item> |
||||
</div> |
||||
<el-form-item prop="summary" label="摘要"> |
||||
<el-input |
||||
style="width: 940px" |
||||
type="textarea" |
||||
v-model.trim="form.summary" |
||||
:rows="3" |
||||
clearable |
||||
></el-input> |
||||
</el-form-item> |
||||
<el-form-item prop="titleImg" label="封面图"> |
||||
<el-upload |
||||
class="avatar-uploader" |
||||
accept=".jpg,.png,.jpeg,.gif" |
||||
:on-change="file => changeFile(file, 0)" |
||||
:show-file-list="false" |
||||
:action="this.api.fileupload" |
||||
:auto-upload="false" |
||||
> |
||||
<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="mainBody" label="正文"> |
||||
<Editor api-key='rnk6zw9v267xqz7pf98twt1vmrvltmd436je7a642pckltda' v-model="form.mainBody" :init="editorConfig" /> |
||||
</el-form-item> |
||||
<el-form-item prop="file" label="文件上传"> |
||||
<el-upload |
||||
:before-upload="fileBeforeUpload" |
||||
:on-remove="handleRemove" |
||||
:on-success="uploadSuccessFile" |
||||
:action="this.api.fileupload" |
||||
:file-list="form.fileList" |
||||
:headers="headers" |
||||
> |
||||
<el-button>上传</el-button> |
||||
</el-upload> |
||||
</el-form-item> |
||||
</el-form> |
||||
<div class="btns"> |
||||
<el-button type="primary" @click="submit(1)">发布</el-button> |
||||
<el-button @click="submit(0)">保存草稿</el-button> |
||||
<el-button @click="back">取消</el-button> |
||||
</div> |
||||
<!-- 剪裁组件弹窗 --> |
||||
<el-dialog title="图片裁剪" append-to-body :visible.sync="cropperModel" width="1100px" :close-on-click-modal="false"> |
||||
<Cropper |
||||
ref="cropper" |
||||
:img-file.sync="file" |
||||
:is-upload="isUpload" |
||||
:fixed="true" |
||||
:fixedNumber.sync="fixedNumber" |
||||
@upload="customUpload" /> |
||||
</el-dialog> |
||||
|
||||
<el-dialog title="所属分类设置" :visible.sync="classVisible" width="500px" :close-on-click-modal="false" class="manage-dia" :before-close="closeClass"> |
||||
<div class="plus"> |
||||
<i class="el-icon-circle-plus-outline" @click="addClass"></i> |
||||
</div> |
||||
<el-table :data="classifications" ref="table" header-align="center" row-key="id"> |
||||
<el-table-column type="index" width="60" label="序号" align="center"></el-table-column> |
||||
<el-table-column prop="classificationName" label="分类名称" align="center" min-width="130"> |
||||
<template slot-scope="scope"> |
||||
<el-input |
||||
v-if="scope.row.edit" |
||||
placeholder="请输入分类名称" |
||||
v-model="scope.row.classificationName" |
||||
clearable |
||||
maxlength="30" |
||||
></el-input> |
||||
<span v-else>{{ scope.row.classificationName }}</span> |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column prop="updateTime1" label="是否引用" align="center" min-width="60">否</el-table-column> |
||||
<el-table-column label="操作" align="center" min-width="60"> |
||||
<template slot-scope="scope"> |
||||
<i v-if="scope.row.edit" class="el-icon-check edit" @click="submitClass(scope.row)"></i> |
||||
<i v-else class="el-icon-edit edit" @click="editClass(scope.row)"></i> |
||||
<i class="el-icon-delete del" @click="delClass(scope.row, scope.$index)"></i> |
||||
</template> |
||||
</el-table-column> |
||||
</el-table> |
||||
<span slot="footer"> |
||||
<el-button @click="closeClass">返回</el-button> |
||||
</span> |
||||
</el-dialog> |
||||
|
||||
<el-dialog title="主题标签设置" :visible.sync="labelVisible" width="500px" :close-on-click-modal="false" class="manage-dia" :before-close="closeLabel"> |
||||
<div class="plus"> |
||||
<i class="el-icon-circle-plus-outline" @click="addLabel"></i> |
||||
</div> |
||||
<el-table :data="labels" ref="table" header-align="center" row-key="id"> |
||||
<el-table-column type="index" width="60" label="序号" align="center"></el-table-column> |
||||
<el-table-column prop="labelName" label="主题名称" align="center" min-width="130"> |
||||
<template slot-scope="scope"> |
||||
<el-input |
||||
v-if="scope.row.edit" |
||||
placeholder="请输入主题名称" |
||||
v-model="scope.row.labelName" |
||||
clearable |
||||
maxlength="30" |
||||
></el-input> |
||||
<span v-else>{{ scope.row.labelName }}</span> |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column prop="updateTime1" label="是否引用" align="center" min-width="60">否</el-table-column> |
||||
<el-table-column label="操作" align="center" min-width="60"> |
||||
<template slot-scope="scope"> |
||||
<i v-if="scope.row.edit" class="el-icon-check edit" @click="submitLabel(scope.row)"></i> |
||||
<i v-else class="el-icon-edit edit" @click="editLabel(scope.row)"></i> |
||||
<i class="el-icon-delete del" @click="delLabel(scope.row, scope.$index)"></i> |
||||
</template> |
||||
</el-table-column> |
||||
</el-table> |
||||
<span slot="footer"> |
||||
<el-button @click="closeLabel">返回</el-button> |
||||
</span> |
||||
</el-dialog> |
||||
</div> |
||||
</template> |
||||
<script> |
||||
import Setting from '@/setting' |
||||
import Util from '@/libs/util' |
||||
import { mapState } from 'vuex' |
||||
import Editor from 'tinymce' |
||||
import editorConfig from './editor' |
||||
import Cropper from '@/components/img-upload/Cropper' |
||||
import Axios from 'axios' |
||||
export default { |
||||
data() { |
||||
return { |
||||
headers: { |
||||
token: sessionStorage.getItem('token') |
||||
}, |
||||
nameRepeat: false, |
||||
sites: [], |
||||
detailStyle: [], |
||||
columns: [], |
||||
articles: [], |
||||
otherArticles: [], |
||||
columnProps: { |
||||
checkStrictly: true, |
||||
value: 'id', |
||||
label: 'columnName' |
||||
}, |
||||
links: [], |
||||
article: '', |
||||
otherColumns: [], |
||||
otherLink: [], |
||||
otherArticle: '', |
||||
form: { |
||||
id: this.$route.query.id || '', |
||||
templateStatus: 0, |
||||
articleTemplate: '', |
||||
doi: '', |
||||
quote: '', |
||||
articleKeyWord: '', |
||||
publicationTypeId: '', |
||||
publicationYear: '', |
||||
periodicalName: '', |
||||
reel: '', |
||||
documentNumber: '', |
||||
activityEndTime: '', |
||||
activityStartTime: '', |
||||
time: '', |
||||
lectureSeries: '', |
||||
onlineLocation: '', |
||||
offlineLocation: '', |
||||
keynoteSpeaker: '', |
||||
eventProfile: '', |
||||
author: '', |
||||
edit: '', |
||||
audit: '', |
||||
bannerImg: '', |
||||
lableId: [], |
||||
classificationId: '', |
||||
columnId: +this.$route.query.columnId, |
||||
file: '', |
||||
isRelease: 0, |
||||
mainBody: '', |
||||
releaseTime: new Date(), |
||||
source: '', |
||||
summary : '', |
||||
title: '', |
||||
titleImg: '', |
||||
connectionType : 1, |
||||
linkAddress: '', |
||||
siteSelection: '', |
||||
fileList: [], |
||||
isOpen: 1 |
||||
}, |
||||
rules: { |
||||
title: [ |
||||
{ required: true, message: '请输入标题', trigger: 'blur' } |
||||
], |
||||
columnId: [ |
||||
{ required: true, message: '请选择所属栏目', trigger: 'change' } |
||||
], |
||||
time: [ |
||||
{ required: true, message: '请选择起始时间', trigger: 'change' } |
||||
], |
||||
classificationId: [ |
||||
{ required: false, message: '请选择所属分类', trigger: 'change' } |
||||
], |
||||
keynoteSpeaker: [ |
||||
{ required: true, message: '请输入主讲人', trigger: 'blur' } |
||||
], |
||||
eventProfile: [ |
||||
{ required: true, message: '请输入活动简介', trigger: 'blur' } |
||||
], |
||||
releaseTime: [ |
||||
{ required: true, message: '请选择发布日期', trigger: 'change' } |
||||
], |
||||
publicationYear: [ |
||||
{ required: true, message: '请选择出版年份', trigger: 'change' } |
||||
], |
||||
titleImg: [ |
||||
{ required: true, message: '请上传封面图', trigger: 'change' } |
||||
], |
||||
mainBody: [ |
||||
{ required: true, message: '请输入正文', trigger: 'blur' } |
||||
], |
||||
connectionType: [ |
||||
{ required: true, message: '请选择连接类型', trigger: 'blur' } |
||||
], |
||||
}, |
||||
columnInfo: {}, |
||||
editorConfig, |
||||
submiting: false, // 新增编辑防抖标识 |
||||
pass: false, |
||||
uploading: 0, |
||||
updateTime: 0, |
||||
cropperModel: false, |
||||
isUpload: false, |
||||
fixedNumber: [1.76, 1], |
||||
file: {}, // 当前被选择的图片文件 |
||||
isBanner: 0, |
||||
classifications: [], |
||||
classVisible: false, |
||||
labels: [], |
||||
labelVisible: false |
||||
}; |
||||
}, |
||||
components: { |
||||
Editor, |
||||
Cropper |
||||
}, |
||||
watch: { |
||||
// 监听信息是否有更改,有的话页面离开的时候要询问是否要保存 |
||||
form: { |
||||
handler(val){ |
||||
this.updateTime++ |
||||
}, |
||||
deep:true |
||||
} |
||||
}, |
||||
// 页面离开的时候如果没有保存则提示 |
||||
beforeRouteLeave(to, from, next) { |
||||
if (this.submiting) { |
||||
next() |
||||
} else if (!this.pass) { |
||||
// 更改了信息才需要提示 |
||||
if (this.updateTime > 1) { |
||||
this.$confirm(`所填写内容暂未保存,是否保存?`, '提示', { |
||||
type: 'warning' |
||||
}).then(() => { |
||||
this.submit(this.form.isRelease, next) |
||||
}).catch(() => { |
||||
next() |
||||
}) |
||||
} else { |
||||
next() |
||||
} |
||||
} else { |
||||
next() |
||||
} |
||||
}, |
||||
mounted() { |
||||
this.getArticle() |
||||
this.getLabel() |
||||
}, |
||||
methods: { |
||||
// 文章列表 |
||||
getArticle() { |
||||
this.$post(this.api.queryArticle, { |
||||
pageNum: 1, |
||||
pageSize: 1000, |
||||
title: '', |
||||
isDisable: 0 |
||||
}).then(({ data }) => { |
||||
this[inner ? 'articles' : 'otherArticles'] = data.records.filter(e => e.isRelease) // 只显示已发布的文章 |
||||
}).catch(err => {}) |
||||
}, |
||||
// 获取所属分类 |
||||
getClassification() { |
||||
this.$post(`${this.api.queryClassif}?siteId=${this.site.id}&templateId=${this.columnInfo.templateId}`).then(({ data }) => { |
||||
this.classifications = data |
||||
}).catch(err => {}) |
||||
}, |
||||
// 显示所属分类弹框 |
||||
setClass() { |
||||
this.classVisible = true |
||||
}, |
||||
// 新增所属分类 |
||||
addClass() { |
||||
this.classifications.push({ |
||||
edit: true, |
||||
id: '', |
||||
classificationName: '' |
||||
}) |
||||
}, |
||||
// 编辑所属分类 |
||||
editClass(row) { |
||||
this.$set(row, 'edit', 1) |
||||
}, |
||||
// 删除所属分类 |
||||
delClass(row, i) { |
||||
if (row.id) { |
||||
this.$confirm('确定要删除吗?', '提示', { |
||||
type: 'warning' |
||||
}).then(() => { |
||||
this.$post(`${this.api.delClassif}?id=${row.id}`).then(res => { |
||||
Util.successMsg('删除成功') |
||||
this.getClassification() |
||||
}).catch(res => {}) |
||||
}).catch(() => {}) |
||||
} else { |
||||
this.classifications.splice(i, 1) |
||||
} |
||||
}, |
||||
// 提交所属分类 |
||||
submitClass(row, showMsg = 1) { |
||||
if (!row.classificationName) return Util.errorMsg('请输入分类名称') |
||||
this.$post(`${this.api.checkClassif}?classificationName=${row.classificationName}&siteId=${this.site.id}&classificationId=${row.id}`).then(res => { |
||||
this.$post(this.api[row.id ? 'updateClassif' : 'saveClassif'], { |
||||
classificationName: row.classificationName, |
||||
templateId: this.columnInfo.templateId, |
||||
id: row.id, |
||||
siteId: this.site.id, |
||||
editorId: this.userId, |
||||
founderId: this.userId |
||||
}).then(res => { |
||||
showMsg && Util.successMsg((row.id ? '修改' : '新增') + '成功') |
||||
this.getClassification() |
||||
}).catch(res => {}) |
||||
}).catch(res => {}) |
||||
}, |
||||
// 关闭所属分类 |
||||
closeClass() { |
||||
const list = this.classifications |
||||
if (list.find(e => e.edit && e.classificationName)) { |
||||
this.$confirm('所填写内容暂未保存,是否保存?', '提示', { |
||||
type: 'warning' |
||||
}).then(() => { |
||||
list.map(e => { |
||||
e.edit && e.classificationName && this.submitClass(e, 0) |
||||
}) |
||||
this.classVisible = false |
||||
}).catch(() => { |
||||
this.classVisible = false |
||||
}) |
||||
} else { |
||||
this.classVisible = false |
||||
} |
||||
}, |
||||
|
||||
|
||||
// 获取标签 |
||||
getLabel() { |
||||
this.$post(`${this.api.queryLabel}?siteId=${this.site.id}`).then(({ data }) => { |
||||
this.labels = data |
||||
}).catch(err => {}) |
||||
}, |
||||
// 显示标签弹框 |
||||
setLabel() { |
||||
this.labelVisible = true |
||||
}, |
||||
// 新增标签 |
||||
addLabel() { |
||||
this.labels.push({ |
||||
edit: true, |
||||
id: '', |
||||
labelName: '' |
||||
}) |
||||
}, |
||||
// 编辑标签 |
||||
editLabel(row) { |
||||
this.$set(row, 'edit', 1) |
||||
}, |
||||
// 删除标签 |
||||
delLabel(row, i) { |
||||
if (row.id) { |
||||
this.$confirm('确定要删除吗?', '提示', { |
||||
type: 'warning' |
||||
}).then(() => { |
||||
this.$post(`${this.api.delLabel}?id=${row.id}`).then(res => { |
||||
Util.successMsg('删除成功') |
||||
this.getLabel() |
||||
}).catch(res => {}) |
||||
}).catch(() => {}) |
||||
} else { |
||||
this.labels.splice(i, 1) |
||||
} |
||||
}, |
||||
// 提交标签 |
||||
submitLabel(row, showMsg = 1) { |
||||
if (!row.labelName) return Util.errorMsg('请输入主题名称') |
||||
this.$post(`${this.api.checkLabel}?labelName=${row.labelName}&siteId=${this.site.id}&labelId=${row.id}`).then(res => { |
||||
this.$post(this.api[row.id ? 'updateLabel' : 'saveLabel'], { |
||||
labelName: row.labelName, |
||||
id: row.id, |
||||
siteId: this.site.id, |
||||
editorId: this.userId, |
||||
founderId: this.userId |
||||
}).then(res => { |
||||
showMsg && Util.successMsg((row.id ? '修改' : '新增') + '成功') |
||||
this.getLabel() |
||||
}).catch(res => {}) |
||||
}).catch(res => {}) |
||||
}, |
||||
// 关闭所属分类 |
||||
closeLabel() { |
||||
const list = this.labels |
||||
if (list.find(e => e.edit && e.labelName)) { |
||||
this.$confirm('所填写内容暂未保存,是否保存?', '提示', { |
||||
type: 'warning' |
||||
}).then(() => { |
||||
list.map(e => { |
||||
e.edit && e.labelName && this.submitLabel(e, 0) |
||||
}) |
||||
this.labelVisible = false |
||||
}).catch(() => { |
||||
this.labelVisible = false |
||||
}) |
||||
} else { |
||||
this.labelVisible = false |
||||
} |
||||
}, |
||||
|
||||
// 文章名称判重 |
||||
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 |
||||
} |
||||
}, |
||||
// 图片裁剪上传事件 |
||||
customUpload(data) { |
||||
const formData = new FormData() |
||||
formData.append('file', data, this.file.name) |
||||
this.imgUpload(formData) |
||||
}, |
||||
// 压缩图片 |
||||
compress(img) { |
||||
const canvas = document.createElement('canvas') |
||||
const ctx = canvas.getContext('2d') |
||||
// let initSize = img.src.length; |
||||
const width = img.width |
||||
const height = img.height |
||||
canvas.width = width |
||||
canvas.height = height |
||||
// 铺底色 |
||||
ctx.fillStyle = '#fff' |
||||
ctx.fillRect(0, 0, canvas.width, canvas.height) |
||||
ctx.drawImage(img, 0, 0, width, height) |
||||
// 进行压缩 |
||||
const ndata = canvas.toDataURL('image/jpeg', 0.8) |
||||
return ndata |
||||
}, |
||||
// base64转成bolb对象 |
||||
dataURItoBlob(base64Data) { |
||||
let byteString |
||||
if (base64Data.split(',')[0].indexOf('base64') >= 0) { |
||||
byteString = atob(base64Data.split(',')[1]) |
||||
} else { |
||||
byteString = unescape(base64Data.split(',')[1]) |
||||
} |
||||
const mimeString = base64Data |
||||
.split(',')[0] |
||||
.split(':')[1] |
||||
.split(';')[0] |
||||
const ia = new Uint8Array(byteString.length) |
||||
for (let i = 0; i < byteString.length; i++) { |
||||
ia[i] = byteString.charCodeAt(i) |
||||
} |
||||
return new Blob([ia], { |
||||
type: mimeString |
||||
}) |
||||
}, |
||||
// 图片上传到服务器 |
||||
imgUpload(formData) { |
||||
this.isUpload = true |
||||
Axios({ |
||||
method: 'post', |
||||
url: this.api.upload, |
||||
data: formData, |
||||
headers: { |
||||
'Content-Type': 'multipart/form-data', |
||||
token: Util.local.get(Setting.tokenKey) |
||||
}, |
||||
}).then(({ data }) => { |
||||
let url = this.form[this.isBanner ? 'bannerImg' : 'titleImg'] |
||||
url && this.$del(this.api.delFile, [url.split('/').pop()]).then(res => {}).catch(e => {}) // 删除替换掉的图片 |
||||
this.form[this.isBanner ? 'bannerImg' : 'titleImg'] = data.url |
||||
}).catch(res => {}) |
||||
this.$refs.cropper.isDisabled = false |
||||
this.isUpload = false |
||||
this.cropperModel = false |
||||
}, |
||||
// 图片改变钩子 |
||||
changeFile(file, isBanner) { |
||||
this.fixedNumber = isBanner ? [1, 0.26] : [1.76, 1] |
||||
this.isBanner = isBanner |
||||
const { size, name } = file |
||||
const ext = name.substring(name.lastIndexOf('.') + 1) |
||||
if (!Util.isImg(ext)) { |
||||
this.$message.error('请上传图片!') |
||||
return false |
||||
} |
||||
// if (size / 1024 / 1024 > 5) { |
||||
// this.$message.error('请上传5M以内的图片!') |
||||
// return false |
||||
// } |
||||
this.file = file |
||||
this.cropperModel = true |
||||
this.$nextTick(() => { |
||||
this.$refs.cropper.updateImg({ |
||||
url: window.URL.createObjectURL(file.raw), |
||||
size: file.size |
||||
}) |
||||
}) |
||||
}, |
||||
// 附件删除 |
||||
handleRemove(e, fileList) { |
||||
e.id ? this.$post(`${this.api.delContentFile}?id=${e.id}`).then(res => { |
||||
this.form.fileList = fileList |
||||
}).catch(res => {}) : (this.form.fileList = fileList) |
||||
}, |
||||
// banner上传成功 |
||||
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 |
||||
}, |
||||
// 附件上传之前的钩子 |
||||
fileBeforeUpload(file) { |
||||
this.uploading++ |
||||
}, |
||||
// 附件上传成功 |
||||
uploadSuccessFile(res) { |
||||
this.uploading-- |
||||
this.form.id ? |
||||
this.$post(this.api.saveContentFile, { |
||||
contentId: this.form.id, |
||||
editorId: this.userId, |
||||
founderId: this.userId, |
||||
id: '', |
||||
fileName: res.original, |
||||
filePath: res.url |
||||
}).then(({ data }) => { |
||||
this.form.fileList.push({ |
||||
name: res.original, |
||||
url: res.url, |
||||
id: data |
||||
}) |
||||
}).catch(res => {}) : |
||||
this.form.fileList.push({ |
||||
name: res.original, |
||||
url: res.url |
||||
}) |
||||
}, |
||||
// 预览 |
||||
preview() { |
||||
window.open((Setting.isDev ? `http://${location.hostname}:8095` : this.$store.state.content.site.domainName) + `#/article?articleId=${this.form.id}&siteId=${this.form.siteId}&id=${this.form.columnId}`) |
||||
}, |
||||
// 返回 |
||||
back() { |
||||
this.pass = true |
||||
const { updateTime } = this |
||||
// 更改了信息才需要提示 |
||||
if (updateTime > 1) { |
||||
this.$confirm(`所填写内容暂未保存,是否保存?`, '提示', { |
||||
type: 'warning' |
||||
}).then(() => { |
||||
this.submit(this.form.isRelease) |
||||
}).catch(() => { |
||||
this.$router.back() |
||||
}) |
||||
} else { |
||||
this.$router.back() |
||||
} |
||||
}, |
||||
// 更新附件的状态为发布 |
||||
updateFile(files, form, quoteId) { |
||||
files.map(e => { |
||||
this.$post(this.api.updateFile, { |
||||
id: e, |
||||
isRelease: form.isRelease, |
||||
quote: form.title, |
||||
quoteId |
||||
}).then(res => {}).catch(err => {}) |
||||
}) |
||||
}, |
||||
// 提交 |
||||
submit(isRelease, next) { |
||||
if (this.submiting) return false |
||||
const form = JSON.parse(JSON.stringify(this.form)) |
||||
if (!form.title) return Util.errorMsg('请填写标题') |
||||
if (this.nameRepeat) return Util.errorMsg('该标题已重复!') |
||||
if (typeof form.fatherId === 'object') form.fatherId = form.fatherId[form.fatherId.length - 1] |
||||
const tId = form.articleTemplate |
||||
// 如果是发布 |
||||
if (isRelease) { |
||||
if (tId !== 25) { |
||||
if (!form.releaseTime) return Util.errorMsg('请选择发布日期') |
||||
} |
||||
if (tId === 22 || tId === 23 || tId === 24) { |
||||
if (!form.titleImg ) return Util.errorMsg('请上传封面') |
||||
} |
||||
if (tId === 25) { |
||||
if ((!form.time || !form.time.length) && isRelease) return Util.errorMsg('请选择起止时间') |
||||
form.activityStartTime = form.time[0] |
||||
form.activityEndTime = form.time[1] |
||||
} |
||||
if (tId === 24 && form.connectionType !== 2) { |
||||
if (form.connectionType === 1) { |
||||
if (!this.links.length) return Util.errorMsg('请选择站内链接') |
||||
} |
||||
if (!this.otherLink.length && form.connectionType === 3) { |
||||
if (!this.otherLink.length) return Util.errorMsg('请选择栏目') |
||||
} |
||||
} |
||||
if ((tId === 22 || tId === 23 || tId === 25) && !form.mainBody) return Util.errorMsg('请输入正文') |
||||
} |
||||
if (this.uploading) return Util.errorMsg('文件正在上传,请上传完成后再发布') |
||||
if (form.connectionType === 1) { |
||||
form.linkAddress = this.links.join() |
||||
if (this.article) form.linkAddress += '-' + this.article |
||||
} else if (form.connectionType === 3) { |
||||
form.linkAddress = this.otherLink.join() |
||||
if (this.otherArticle) form.linkAddress += '-' + this.otherArticle |
||||
} |
||||
const { columnId, bannerImg, fileList, titleImg } = form |
||||
const fileId = [] |
||||
if (typeof columnId === 'object') form.columnId = columnId[columnId.length - 1] // 如果更换了栏目id,值会变成数组,需要手动获取最后一个 |
||||
// 获取几个附件的id,url后面的数字串即是附件id |
||||
if (bannerImg) fileId.push(bannerImg.substr(bannerImg.lastIndexOf('/') + 1)) |
||||
if (titleImg) fileId.push(titleImg.substr(titleImg.lastIndexOf('/') + 1)) |
||||
fileList && fileList.map(e => { |
||||
fileId.push(e[e.url ? 'url' : 'filePath'].substr(e[e.url ? 'url' : 'filePath'].lastIndexOf('/') + 1)) |
||||
}) |
||||
form.lableId = form.lableId.join(',') |
||||
|
||||
form.releaseTime = Util.formatDate('yyyy-MM-dd', new Date(form.releaseTime)) // 发布日期转化为年月日格式 |
||||
|
||||
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 => { |
||||
this.updateFile(fileId, form, form.id) |
||||
Util.successMsg('修改成功') |
||||
next ? next() : this.$router.push(`list?columnId=` + form.columnId) |
||||
}).catch(err => { |
||||
this.submiting = false |
||||
}) |
||||
} else { |
||||
this.$post(this.api.saveArticle, form).then(({ data }) => { |
||||
this.updateFile(fileId, form, data) |
||||
// 新增文章完后需要把上传的附件添加到文章附件表 |
||||
form.fileList.map(e => { |
||||
this.$post(this.api.saveContentFile, { |
||||
contentId: data, |
||||
editorId: this.userId, |
||||
founderId: this.userId, |
||||
id: '', |
||||
fileName: e.name, |
||||
filePath: e.url |
||||
}).then(res => {}).catch(err => {}) |
||||
}) |
||||
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; |
||||
flex-wrap: wrap; |
||||
width: 955px; |
||||
// height: 320px; |
||||
margin-top: 20px; |
||||
overflow: auto; |
||||
li { |
||||
margin: 0 20px 10px 0; |
||||
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; |
||||
img { |
||||
width: 80px; |
||||
} |
||||
.is-link { |
||||
width: 50px; |
||||
} |
||||
} |
||||
} |
||||
.info { |
||||
position: absolute; |
||||
top: 8px; |
||||
left: -32px; |
||||
cursor: pointer; |
||||
} |
||||
.plus { |
||||
margin-bottom: 10px; |
||||
font-size: 18px; |
||||
color: #2962FF; |
||||
text-align: right; |
||||
cursor: pointer; |
||||
} |
||||
.set-btn { |
||||
margin-left: 10px !important; |
||||
} |
||||
.manage-dia { |
||||
.edit, .del { |
||||
font-size: 14px; |
||||
cursor: pointer; |
||||
} |
||||
.edit { |
||||
margin-right: 10px; |
||||
} |
||||
} |
||||
.input-form { |
||||
&.model { |
||||
height: calc(100vh - 200px); |
||||
padding-right: 20px; |
||||
overflow: auto; |
||||
.el-form-item__label { |
||||
padding-right: 20px; |
||||
} |
||||
.lg .el-form-item__label { |
||||
padding-right: 43px; |
||||
} |
||||
} |
||||
.item-line { |
||||
display: flex; |
||||
.el-form-item:not(:last-child) { |
||||
margin-right: 200px; |
||||
} |
||||
} |
||||
.line { |
||||
margin-bottom: 24px; |
||||
border-bottom: 1px dashed #C2C2C2; |
||||
} |
||||
.el-form-item--small.el-form-item { |
||||
margin-bottom: 24px; |
||||
} |
||||
.el-input, .el-select { |
||||
width: 300px; |
||||
} |
||||
.el-select .el-input { |
||||
width: auto; |
||||
} |
||||
.el-textarea { |
||||
width: 550px; |
||||
} |
||||
.auto, .auto .el-input { |
||||
width: auto; |
||||
} |
||||
.el-form-item.is-required:not(.is-no-asterisk) > .el-form-item__label:before { |
||||
font-size: 18px; |
||||
vertical-align: -4px; |
||||
color: #F5222D; |
||||
} |
||||
} |
||||
.btns { |
||||
text-align: center; |
||||
} |
||||
</style> |
@ -0,0 +1,187 @@ |
||||
<template> |
||||
<div class="page"> |
||||
<div class="tool"> |
||||
<div class="search-wrap"> |
||||
<el-input class="keyword" placeholder="请输入标题" v-model.trim="keyword" clearable></el-input> |
||||
</div> |
||||
<div class="actions"> |
||||
<el-button v-auth="'/site/list:内容管理:文章管理:删除'" @click="batchDel">批量删除</el-button> |
||||
<el-button v-auth="'/site/list:内容管理:文章管理:新增'" type="primary" @click="add" >新增文章</el-button> |
||||
</div> |
||||
</div> |
||||
<el-table :data="list" class="table" ref="table" header-align="center" @selection-change="handleSelectionChange" row-key="id" @sort-change="sortChange"> |
||||
<el-table-column type="selection" width="55" align="center" :reserve-selection="true"></el-table-column> |
||||
<el-table-column type="index" width="60" label="序号" align="center"></el-table-column> |
||||
<el-table-column show-overflow-tooltip prop="title" label="标题" align="center" min-width="150"></el-table-column> |
||||
<el-table-column prop="classificationName" label="所属分类" align="center" min-width="120" sortable="custom"></el-table-column> |
||||
<el-table-column prop="founderName" label="录入人" align="center" min-width="80"></el-table-column> |
||||
<el-table-column prop="editorName" label="修改人" align="center" min-width="80"></el-table-column> |
||||
<el-table-column prop="updateTime" label="修改日期" align="center" min-width="150"></el-table-column> |
||||
<el-table-column prop="releaseTime" label="发布日期" align="center" min-width="100"></el-table-column> |
||||
<el-table-column prop="totalBrowsing" label="已学习人数" align="center" min-width="70"></el-table-column> |
||||
<el-table-column prop="workNumber" label="状态" align="center" min-width="80"> |
||||
<template slot-scope="scope"> |
||||
{{ scope.row.isRelease ? '已发布' : '草稿' }} |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column label="操作" align="center" width="170"> |
||||
<template slot-scope="scope"> |
||||
<el-button v-auth="'/site/list:内容管理:文章管理:编辑'" type="text" @click="edit(scope.row)">编辑</el-button> |
||||
<el-button v-auth="'/site/list:内容管理:文章管理:删除'" type="text" @click="handleDelete(scope.row)">删除</el-button> |
||||
<el-switch |
||||
class="m-l-10" |
||||
v-model="scope.row.isDisable" |
||||
:active-value="0" |
||||
:inactive-value="1" |
||||
@change="switchOff($event, scope.row, scope.$index)"> |
||||
</el-switch> |
||||
</template> |
||||
</el-table-column> |
||||
</el-table> |
||||
<div class="pagination"> |
||||
<el-pagination background @current-change="currentChange" :current-page="page" layout="total, prev, pager, next" :total="total"></el-pagination> |
||||
</div> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
import Setting from '@/setting' |
||||
import util from '@/libs/util' |
||||
import { mapMutations } from 'vuex' |
||||
export default { |
||||
data() { |
||||
return { |
||||
keyword: '', |
||||
list: [], |
||||
page: 1, |
||||
pageSize: 10, |
||||
total: 0, |
||||
modifiedTimeSort: '', |
||||
publicationTimeSort: '', |
||||
ordinalSort: 0, |
||||
multipleSelection: [], |
||||
}; |
||||
}, |
||||
watch: { |
||||
keyword: function(val) { |
||||
clearTimeout(this.searchTimer) |
||||
this.searchTimer = setTimeout(() => { |
||||
this.initData() |
||||
}, 500) |
||||
} |
||||
}, |
||||
mounted() { |
||||
// this.getData() |
||||
}, |
||||
methods: { |
||||
// 文章列表 |
||||
getData() { |
||||
const { keyword } = this |
||||
const data = { |
||||
pageNum: this.page, |
||||
pageSize: this.pageSize, |
||||
ordinalSort: this.ordinalSort, |
||||
title: this.field === 'title' ? keyword : '', |
||||
founder: this.field === 'founder' ? keyword : '', |
||||
column: this.field === 'column' ? keyword : '', |
||||
editor: this.field === 'editor' ? keyword : '' |
||||
} |
||||
if (this.modifiedTimeSort !== '') data.modifiedTimeSort = this.modifiedTimeSort |
||||
if (this.publicationTimeSort !== '') data.publicationTimeSort = this.publicationTimeSort |
||||
this.$post(this.api.queryArticle, data).then(({ data }) => { |
||||
this.list = data.records |
||||
this.total = +data.total |
||||
}).catch(err => {}) |
||||
}, |
||||
currentChange(val) { |
||||
this.page = val |
||||
this.getData() |
||||
}, |
||||
handleSelectionChange(val) { |
||||
this.multipleSelection = val |
||||
}, |
||||
initData() { |
||||
this.$refs.table.clearSelection() |
||||
this.page = 1 |
||||
this.getData() |
||||
}, |
||||
// 批量删除 |
||||
batchDel() { |
||||
const list = this.multipleSelection |
||||
if (list.length) { |
||||
this.$confirm('确定要删除吗?', '提示', { |
||||
type: 'warning' |
||||
}).then(() => { |
||||
const data = [] |
||||
list.map(e => { |
||||
data.push('ids=' + e.id) |
||||
}) |
||||
this.$post(`${this.api.deleteArticle}?${data.join('&')}`).then(res => { |
||||
this.$refs.table.clearSelection() |
||||
util.successMsg("删除成功") |
||||
this.getData() |
||||
}).catch(res => {}) |
||||
}).catch(() => {}) |
||||
} else { |
||||
util.errorMsg('请先选择数据 !') |
||||
} |
||||
}, |
||||
// 删除 |
||||
handleDelete(row) { |
||||
this.$confirm('确定要删除吗?', '提示', { |
||||
type: 'warning' |
||||
}).then(() => { |
||||
this.$post(`${this.api.deleteArticle}?ids=${row.id}`).then(res => { |
||||
util.successMsg('删除成功') |
||||
this.getData() |
||||
}).catch(res => {}) |
||||
}).catch(() => {}) |
||||
}, |
||||
// 禁用启用 |
||||
switchOff(val, row) { |
||||
this.$post(`${this.api.articleEnableOrDisable}?id=${row.id}&isDisable=${val}`).then(res => {}).catch((res) => {}) |
||||
}, |
||||
// 新增 |
||||
add() { |
||||
this.$router.push(`/schemeSet`) |
||||
}, |
||||
// 排序回调 |
||||
sortChange(column) { |
||||
const { order } = column |
||||
// 三个排序只能同时传1个,所以点了一个排序的时候要清除掉其余两个 |
||||
// 两个时间0默认倒序 1升序 |
||||
if (column.prop === 'updateTime') { |
||||
this.modifiedTimeSort = order ? order === 'ascending' ? 1 : 0 : '' |
||||
if (order) { |
||||
this.publicationTimeSort = '' |
||||
this.ordinalSort = '' |
||||
} |
||||
} |
||||
if (column.prop === 'releaseTime') { |
||||
this.publicationTimeSort = order ? order === 'ascending' ? 1 : 0 : '' |
||||
if (order) { |
||||
this.modifiedTimeSort = '' |
||||
this.ordinalSort = '' |
||||
} |
||||
} |
||||
// 序号排序 0默认升序 1倒序 |
||||
if (column.prop === 'sequence') { |
||||
this.ordinalSort = order ? order === 'ascending' ? 0 : 1 : '' |
||||
if (order) { |
||||
this.publicationTimeSort = '' |
||||
this.modifiedTimeSort = '' |
||||
} |
||||
} |
||||
this.getData() |
||||
}, |
||||
// 编辑 |
||||
edit(row) { |
||||
this.$router.push(`add?id=${row.id}&columnId=${this.$refs.column.getCurrentKey()}&columnName=${this.$refs.column.getCurrentNode().columnName}`) |
||||
}, |
||||
} |
||||
}; |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
|
||||
</style> |
@ -0,0 +1,187 @@ |
||||
<template> |
||||
<div class="page"> |
||||
<div class="tool"> |
||||
<div class="search-wrap"> |
||||
<el-input class="keyword" placeholder="请输入标题" v-model.trim="keyword" clearable></el-input> |
||||
</div> |
||||
<div class="actions"> |
||||
<el-button v-auth="'/site/list:内容管理:文章管理:删除'" @click="batchDel">批量删除</el-button> |
||||
<el-button v-auth="'/site/list:内容管理:文章管理:新增'" type="primary" @click="add" >新增文章</el-button> |
||||
</div> |
||||
</div> |
||||
<el-table :data="list" class="table" ref="table" header-align="center" @selection-change="handleSelectionChange" row-key="id" @sort-change="sortChange"> |
||||
<el-table-column type="selection" width="55" align="center" :reserve-selection="true"></el-table-column> |
||||
<el-table-column type="index" width="60" label="序号" align="center"></el-table-column> |
||||
<el-table-column show-overflow-tooltip prop="title" label="标题" align="center" min-width="150"></el-table-column> |
||||
<el-table-column prop="classificationName" label="所属分类" align="center" min-width="120" sortable="custom"></el-table-column> |
||||
<el-table-column prop="founderName" label="录入人" align="center" min-width="80"></el-table-column> |
||||
<el-table-column prop="editorName" label="修改人" align="center" min-width="80"></el-table-column> |
||||
<el-table-column prop="updateTime" label="修改日期" align="center" min-width="150"></el-table-column> |
||||
<el-table-column prop="releaseTime" label="发布日期" align="center" min-width="100"></el-table-column> |
||||
<el-table-column prop="totalBrowsing" label="总浏览" align="center" min-width="70"></el-table-column> |
||||
<el-table-column prop="workNumber" label="状态" align="center" min-width="80"> |
||||
<template slot-scope="scope"> |
||||
{{ scope.row.isRelease ? '已发布' : '草稿' }} |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column label="操作" align="center" width="170"> |
||||
<template slot-scope="scope"> |
||||
<el-button v-auth="'/site/list:内容管理:文章管理:编辑'" type="text" @click="edit(scope.row)">编辑</el-button> |
||||
<el-button v-auth="'/site/list:内容管理:文章管理:删除'" type="text" @click="handleDelete(scope.row)">删除</el-button> |
||||
<el-switch |
||||
class="m-l-10" |
||||
v-model="scope.row.isDisable" |
||||
:active-value="0" |
||||
:inactive-value="1" |
||||
@change="switchOff($event, scope.row, scope.$index)"> |
||||
</el-switch> |
||||
</template> |
||||
</el-table-column> |
||||
</el-table> |
||||
<div class="pagination"> |
||||
<el-pagination background @current-change="currentChange" :current-page="page" layout="total, prev, pager, next" :total="total"></el-pagination> |
||||
</div> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
import Setting from '@/setting' |
||||
import util from '@/libs/util' |
||||
import { mapMutations } from 'vuex' |
||||
export default { |
||||
data() { |
||||
return { |
||||
keyword: '', |
||||
list: [], |
||||
page: 1, |
||||
pageSize: 10, |
||||
total: 0, |
||||
modifiedTimeSort: '', |
||||
publicationTimeSort: '', |
||||
ordinalSort: 0, |
||||
multipleSelection: [], |
||||
}; |
||||
}, |
||||
watch: { |
||||
keyword: function(val) { |
||||
clearTimeout(this.searchTimer) |
||||
this.searchTimer = setTimeout(() => { |
||||
this.initData() |
||||
}, 500) |
||||
} |
||||
}, |
||||
mounted() { |
||||
// this.getData() |
||||
}, |
||||
methods: { |
||||
// 文章列表 |
||||
getData() { |
||||
const { keyword } = this |
||||
const data = { |
||||
pageNum: this.page, |
||||
pageSize: this.pageSize, |
||||
ordinalSort: this.ordinalSort, |
||||
title: this.field === 'title' ? keyword : '', |
||||
founder: this.field === 'founder' ? keyword : '', |
||||
column: this.field === 'column' ? keyword : '', |
||||
editor: this.field === 'editor' ? keyword : '' |
||||
} |
||||
if (this.modifiedTimeSort !== '') data.modifiedTimeSort = this.modifiedTimeSort |
||||
if (this.publicationTimeSort !== '') data.publicationTimeSort = this.publicationTimeSort |
||||
this.$post(this.api.queryArticle, data).then(({ data }) => { |
||||
this.list = data.records |
||||
this.total = +data.total |
||||
}).catch(err => {}) |
||||
}, |
||||
currentChange(val) { |
||||
this.page = val |
||||
this.getData() |
||||
}, |
||||
handleSelectionChange(val) { |
||||
this.multipleSelection = val |
||||
}, |
||||
initData() { |
||||
this.$refs.table.clearSelection() |
||||
this.page = 1 |
||||
this.getData() |
||||
}, |
||||
// 批量删除 |
||||
batchDel() { |
||||
const list = this.multipleSelection |
||||
if (list.length) { |
||||
this.$confirm('确定要删除吗?', '提示', { |
||||
type: 'warning' |
||||
}).then(() => { |
||||
const data = [] |
||||
list.map(e => { |
||||
data.push('ids=' + e.id) |
||||
}) |
||||
this.$post(`${this.api.deleteArticle}?${data.join('&')}`).then(res => { |
||||
this.$refs.table.clearSelection() |
||||
util.successMsg("删除成功") |
||||
this.getData() |
||||
}).catch(res => {}) |
||||
}).catch(() => {}) |
||||
} else { |
||||
util.errorMsg('请先选择数据 !') |
||||
} |
||||
}, |
||||
// 删除 |
||||
handleDelete(row) { |
||||
this.$confirm('确定要删除吗?', '提示', { |
||||
type: 'warning' |
||||
}).then(() => { |
||||
this.$post(`${this.api.deleteArticle}?ids=${row.id}`).then(res => { |
||||
util.successMsg('删除成功') |
||||
this.getData() |
||||
}).catch(res => {}) |
||||
}).catch(() => {}) |
||||
}, |
||||
// 禁用启用 |
||||
switchOff(val, row) { |
||||
this.$post(`${this.api.articleEnableOrDisable}?id=${row.id}&isDisable=${val}`).then(res => {}).catch((res) => {}) |
||||
}, |
||||
// 新增 |
||||
add() { |
||||
this.$router.push(`/learnMg`) |
||||
}, |
||||
// 排序回调 |
||||
sortChange(column) { |
||||
const { order } = column |
||||
// 三个排序只能同时传1个,所以点了一个排序的时候要清除掉其余两个 |
||||
// 两个时间0默认倒序 1升序 |
||||
if (column.prop === 'updateTime') { |
||||
this.modifiedTimeSort = order ? order === 'ascending' ? 1 : 0 : '' |
||||
if (order) { |
||||
this.publicationTimeSort = '' |
||||
this.ordinalSort = '' |
||||
} |
||||
} |
||||
if (column.prop === 'releaseTime') { |
||||
this.publicationTimeSort = order ? order === 'ascending' ? 1 : 0 : '' |
||||
if (order) { |
||||
this.modifiedTimeSort = '' |
||||
this.ordinalSort = '' |
||||
} |
||||
} |
||||
// 序号排序 0默认升序 1倒序 |
||||
if (column.prop === 'sequence') { |
||||
this.ordinalSort = order ? order === 'ascending' ? 0 : 1 : '' |
||||
if (order) { |
||||
this.publicationTimeSort = '' |
||||
this.modifiedTimeSort = '' |
||||
} |
||||
} |
||||
this.getData() |
||||
}, |
||||
// 编辑 |
||||
edit(row) { |
||||
this.$router.push(`add?id=${row.id}&columnId=${this.$refs.column.getCurrentKey()}&columnName=${this.$refs.column.getCurrentNode().columnName}`) |
||||
}, |
||||
} |
||||
}; |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
|
||||
</style> |
@ -0,0 +1,891 @@ |
||||
<template> |
||||
<div class="page"> |
||||
<p class="page-name mb">方案设置</p> |
||||
<el-form :model="form" :rules="rules" class="input-form model" label-width="140px"> |
||||
<div class="item-line"> |
||||
<el-form-item prop="source" label="标题"> |
||||
<el-input |
||||
placeholder="请输入标题" |
||||
v-model.trim="form.source" |
||||
clearable |
||||
maxlength="30" |
||||
class="inline-input" |
||||
></el-input> |
||||
</el-form-item> |
||||
<el-form-item prop="author" label="所属分类"> |
||||
<el-select style="width: 234px;" v-model="form.classificationId"> |
||||
<template v-for="item in classifications"> |
||||
<el-option |
||||
v-if="item.id" |
||||
:key="item.id" |
||||
:label="item.classificationName" |
||||
:value="item.id"> |
||||
</el-option> |
||||
</template> |
||||
</el-select> |
||||
<el-button class="set-btn" type="primary" @click="setClass">设置</el-button> |
||||
</el-form-item> |
||||
</div> |
||||
<el-form-item prop="summary" label="适用专业"> |
||||
<el-input |
||||
style="width: 940px" |
||||
type="textarea" |
||||
v-model.trim="form.summary" |
||||
:rows="3" |
||||
clearable |
||||
></el-input> |
||||
</el-form-item> |
||||
<el-form-item prop="summary" label="产品"> |
||||
<el-input |
||||
style="width: 940px" |
||||
type="textarea" |
||||
v-model.trim="form.summary" |
||||
:rows="3" |
||||
clearable |
||||
></el-input> |
||||
</el-form-item> |
||||
<el-form-item prop="file" label="文件上传"> |
||||
<el-upload |
||||
:before-upload="fileBeforeUpload" |
||||
:on-remove="handleRemove" |
||||
:on-success="uploadSuccessFile" |
||||
:action="this.api.fileupload" |
||||
:file-list="form.fileList" |
||||
:headers="headers" |
||||
> |
||||
<el-button>上传</el-button> |
||||
</el-upload> |
||||
</el-form-item> |
||||
</el-form> |
||||
<div class="btns"> |
||||
<el-button type="primary" @click="submit(1)">发布</el-button> |
||||
<el-button @click="submit(0)">保存草稿</el-button> |
||||
<el-button @click="back">取消</el-button> |
||||
</div> |
||||
<!-- 剪裁组件弹窗 --> |
||||
<el-dialog title="图片裁剪" append-to-body :visible.sync="cropperModel" width="1100px" :close-on-click-modal="false"> |
||||
<Cropper |
||||
ref="cropper" |
||||
:img-file.sync="file" |
||||
:is-upload="isUpload" |
||||
:fixed="true" |
||||
:fixedNumber.sync="fixedNumber" |
||||
@upload="customUpload" /> |
||||
</el-dialog> |
||||
|
||||
<el-dialog title="所属分类设置" :visible.sync="classVisible" width="500px" :close-on-click-modal="false" class="manage-dia" :before-close="closeClass"> |
||||
<div class="plus"> |
||||
<i class="el-icon-circle-plus-outline" @click="addClass"></i> |
||||
</div> |
||||
<el-table :data="classifications" ref="table" header-align="center" row-key="id"> |
||||
<el-table-column type="index" width="60" label="序号" align="center"></el-table-column> |
||||
<el-table-column prop="classificationName" label="分类名称" align="center" min-width="130"> |
||||
<template slot-scope="scope"> |
||||
<el-input |
||||
v-if="scope.row.edit" |
||||
placeholder="请输入分类名称" |
||||
v-model="scope.row.classificationName" |
||||
clearable |
||||
maxlength="30" |
||||
></el-input> |
||||
<span v-else>{{ scope.row.classificationName }}</span> |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column prop="updateTime1" label="是否引用" align="center" min-width="60">否</el-table-column> |
||||
<el-table-column label="操作" align="center" min-width="60"> |
||||
<template slot-scope="scope"> |
||||
<i v-if="scope.row.edit" class="el-icon-check edit" @click="submitClass(scope.row)"></i> |
||||
<i v-else class="el-icon-edit edit" @click="editClass(scope.row)"></i> |
||||
<i class="el-icon-delete del" @click="delClass(scope.row, scope.$index)"></i> |
||||
</template> |
||||
</el-table-column> |
||||
</el-table> |
||||
<span slot="footer"> |
||||
<el-button @click="closeClass">返回</el-button> |
||||
</span> |
||||
</el-dialog> |
||||
|
||||
<el-dialog title="主题标签设置" :visible.sync="labelVisible" width="500px" :close-on-click-modal="false" class="manage-dia" :before-close="closeLabel"> |
||||
<div class="plus"> |
||||
<i class="el-icon-circle-plus-outline" @click="addLabel"></i> |
||||
</div> |
||||
<el-table :data="labels" ref="table" header-align="center" row-key="id"> |
||||
<el-table-column type="index" width="60" label="序号" align="center"></el-table-column> |
||||
<el-table-column prop="labelName" label="主题名称" align="center" min-width="130"> |
||||
<template slot-scope="scope"> |
||||
<el-input |
||||
v-if="scope.row.edit" |
||||
placeholder="请输入主题名称" |
||||
v-model="scope.row.labelName" |
||||
clearable |
||||
maxlength="30" |
||||
></el-input> |
||||
<span v-else>{{ scope.row.labelName }}</span> |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column prop="updateTime1" label="是否引用" align="center" min-width="60">否</el-table-column> |
||||
<el-table-column label="操作" align="center" min-width="60"> |
||||
<template slot-scope="scope"> |
||||
<i v-if="scope.row.edit" class="el-icon-check edit" @click="submitLabel(scope.row)"></i> |
||||
<i v-else class="el-icon-edit edit" @click="editLabel(scope.row)"></i> |
||||
<i class="el-icon-delete del" @click="delLabel(scope.row, scope.$index)"></i> |
||||
</template> |
||||
</el-table-column> |
||||
</el-table> |
||||
<span slot="footer"> |
||||
<el-button @click="closeLabel">返回</el-button> |
||||
</span> |
||||
</el-dialog> |
||||
</div> |
||||
</template> |
||||
<script> |
||||
import Setting from '@/setting' |
||||
import Util from '@/libs/util' |
||||
import { mapState } from 'vuex' |
||||
import Editor from 'tinymce' |
||||
import editorConfig from './editor' |
||||
import Cropper from '@/components/img-upload/Cropper' |
||||
import Axios from 'axios' |
||||
export default { |
||||
data() { |
||||
return { |
||||
headers: { |
||||
token: sessionStorage.getItem('token') |
||||
}, |
||||
nameRepeat: false, |
||||
sites: [], |
||||
detailStyle: [], |
||||
columns: [], |
||||
articles: [], |
||||
otherArticles: [], |
||||
columnProps: { |
||||
checkStrictly: true, |
||||
value: 'id', |
||||
label: 'columnName' |
||||
}, |
||||
links: [], |
||||
article: '', |
||||
otherColumns: [], |
||||
otherLink: [], |
||||
otherArticle: '', |
||||
form: { |
||||
id: this.$route.query.id || '', |
||||
templateStatus: 0, |
||||
articleTemplate: '', |
||||
doi: '', |
||||
quote: '', |
||||
articleKeyWord: '', |
||||
publicationTypeId: '', |
||||
publicationYear: '', |
||||
periodicalName: '', |
||||
reel: '', |
||||
documentNumber: '', |
||||
activityEndTime: '', |
||||
activityStartTime: '', |
||||
time: '', |
||||
lectureSeries: '', |
||||
onlineLocation: '', |
||||
offlineLocation: '', |
||||
keynoteSpeaker: '', |
||||
eventProfile: '', |
||||
author: '', |
||||
edit: '', |
||||
audit: '', |
||||
bannerImg: '', |
||||
lableId: [], |
||||
classificationId: '', |
||||
columnId: +this.$route.query.columnId, |
||||
file: '', |
||||
isRelease: 0, |
||||
mainBody: '', |
||||
releaseTime: new Date(), |
||||
source: '', |
||||
summary : '', |
||||
title: '', |
||||
titleImg: '', |
||||
connectionType : 1, |
||||
linkAddress: '', |
||||
siteSelection: '', |
||||
fileList: [], |
||||
isOpen: 1 |
||||
}, |
||||
rules: { |
||||
title: [ |
||||
{ required: true, message: '请输入标题', trigger: 'blur' } |
||||
], |
||||
columnId: [ |
||||
{ required: true, message: '请选择所属栏目', trigger: 'change' } |
||||
], |
||||
time: [ |
||||
{ required: true, message: '请选择起始时间', trigger: 'change' } |
||||
], |
||||
classificationId: [ |
||||
{ required: false, message: '请选择所属分类', trigger: 'change' } |
||||
], |
||||
keynoteSpeaker: [ |
||||
{ required: true, message: '请输入主讲人', trigger: 'blur' } |
||||
], |
||||
eventProfile: [ |
||||
{ required: true, message: '请输入活动简介', trigger: 'blur' } |
||||
], |
||||
releaseTime: [ |
||||
{ required: true, message: '请选择发布日期', trigger: 'change' } |
||||
], |
||||
publicationYear: [ |
||||
{ required: true, message: '请选择出版年份', trigger: 'change' } |
||||
], |
||||
titleImg: [ |
||||
{ required: true, message: '请上传封面图', trigger: 'change' } |
||||
], |
||||
mainBody: [ |
||||
{ required: true, message: '请输入正文', trigger: 'blur' } |
||||
], |
||||
connectionType: [ |
||||
{ required: true, message: '请选择连接类型', trigger: 'blur' } |
||||
], |
||||
}, |
||||
columnInfo: {}, |
||||
editorConfig, |
||||
submiting: false, // 新增编辑防抖标识 |
||||
pass: false, |
||||
uploading: 0, |
||||
updateTime: 0, |
||||
cropperModel: false, |
||||
isUpload: false, |
||||
fixedNumber: [1.76, 1], |
||||
file: {}, // 当前被选择的图片文件 |
||||
isBanner: 0, |
||||
classifications: [], |
||||
classVisible: false, |
||||
labels: [], |
||||
labelVisible: false |
||||
}; |
||||
}, |
||||
components: { |
||||
Editor, |
||||
Cropper |
||||
}, |
||||
watch: { |
||||
// 监听信息是否有更改,有的话页面离开的时候要询问是否要保存 |
||||
form: { |
||||
handler(val){ |
||||
this.updateTime++ |
||||
}, |
||||
deep:true |
||||
} |
||||
}, |
||||
// 页面离开的时候如果没有保存则提示 |
||||
beforeRouteLeave(to, from, next) { |
||||
if (this.submiting) { |
||||
next() |
||||
} else if (!this.pass) { |
||||
// 更改了信息才需要提示 |
||||
if (this.updateTime > 1) { |
||||
this.$confirm(`所填写内容暂未保存,是否保存?`, '提示', { |
||||
type: 'warning' |
||||
}).then(() => { |
||||
this.submit(this.form.isRelease, next) |
||||
}).catch(() => { |
||||
next() |
||||
}) |
||||
} else { |
||||
next() |
||||
} |
||||
} else { |
||||
next() |
||||
} |
||||
}, |
||||
mounted() { |
||||
this.getArticle() |
||||
this.getLabel() |
||||
}, |
||||
methods: { |
||||
// 文章列表 |
||||
getArticle() { |
||||
this.$post(this.api.queryArticle, { |
||||
pageNum: 1, |
||||
pageSize: 1000, |
||||
title: '', |
||||
isDisable: 0 |
||||
}).then(({ data }) => { |
||||
this[inner ? 'articles' : 'otherArticles'] = data.records.filter(e => e.isRelease) // 只显示已发布的文章 |
||||
}).catch(err => {}) |
||||
}, |
||||
// 获取所属分类 |
||||
getClassification() { |
||||
this.$post(`${this.api.queryClassif}?siteId=${this.site.id}&templateId=${this.columnInfo.templateId}`).then(({ data }) => { |
||||
this.classifications = data |
||||
}).catch(err => {}) |
||||
}, |
||||
// 显示所属分类弹框 |
||||
setClass() { |
||||
this.classVisible = true |
||||
}, |
||||
// 新增所属分类 |
||||
addClass() { |
||||
this.classifications.push({ |
||||
edit: true, |
||||
id: '', |
||||
classificationName: '' |
||||
}) |
||||
}, |
||||
// 编辑所属分类 |
||||
editClass(row) { |
||||
this.$set(row, 'edit', 1) |
||||
}, |
||||
// 删除所属分类 |
||||
delClass(row, i) { |
||||
if (row.id) { |
||||
this.$confirm('确定要删除吗?', '提示', { |
||||
type: 'warning' |
||||
}).then(() => { |
||||
this.$post(`${this.api.delClassif}?id=${row.id}`).then(res => { |
||||
Util.successMsg('删除成功') |
||||
this.getClassification() |
||||
}).catch(res => {}) |
||||
}).catch(() => {}) |
||||
} else { |
||||
this.classifications.splice(i, 1) |
||||
} |
||||
}, |
||||
// 提交所属分类 |
||||
submitClass(row, showMsg = 1) { |
||||
if (!row.classificationName) return Util.errorMsg('请输入分类名称') |
||||
this.$post(`${this.api.checkClassif}?classificationName=${row.classificationName}&siteId=${this.site.id}&classificationId=${row.id}`).then(res => { |
||||
this.$post(this.api[row.id ? 'updateClassif' : 'saveClassif'], { |
||||
classificationName: row.classificationName, |
||||
templateId: this.columnInfo.templateId, |
||||
id: row.id, |
||||
siteId: this.site.id, |
||||
editorId: this.userId, |
||||
founderId: this.userId |
||||
}).then(res => { |
||||
showMsg && Util.successMsg((row.id ? '修改' : '新增') + '成功') |
||||
this.getClassification() |
||||
}).catch(res => {}) |
||||
}).catch(res => {}) |
||||
}, |
||||
// 关闭所属分类 |
||||
closeClass() { |
||||
const list = this.classifications |
||||
if (list.find(e => e.edit && e.classificationName)) { |
||||
this.$confirm('所填写内容暂未保存,是否保存?', '提示', { |
||||
type: 'warning' |
||||
}).then(() => { |
||||
list.map(e => { |
||||
e.edit && e.classificationName && this.submitClass(e, 0) |
||||
}) |
||||
this.classVisible = false |
||||
}).catch(() => { |
||||
this.classVisible = false |
||||
}) |
||||
} else { |
||||
this.classVisible = false |
||||
} |
||||
}, |
||||
|
||||
|
||||
// 获取标签 |
||||
getLabel() { |
||||
this.$post(`${this.api.queryLabel}?siteId=${this.site.id}`).then(({ data }) => { |
||||
this.labels = data |
||||
}).catch(err => {}) |
||||
}, |
||||
// 显示标签弹框 |
||||
setLabel() { |
||||
this.labelVisible = true |
||||
}, |
||||
// 新增标签 |
||||
addLabel() { |
||||
this.labels.push({ |
||||
edit: true, |
||||
id: '', |
||||
labelName: '' |
||||
}) |
||||
}, |
||||
// 编辑标签 |
||||
editLabel(row) { |
||||
this.$set(row, 'edit', 1) |
||||
}, |
||||
// 删除标签 |
||||
delLabel(row, i) { |
||||
if (row.id) { |
||||
this.$confirm('确定要删除吗?', '提示', { |
||||
type: 'warning' |
||||
}).then(() => { |
||||
this.$post(`${this.api.delLabel}?id=${row.id}`).then(res => { |
||||
Util.successMsg('删除成功') |
||||
this.getLabel() |
||||
}).catch(res => {}) |
||||
}).catch(() => {}) |
||||
} else { |
||||
this.labels.splice(i, 1) |
||||
} |
||||
}, |
||||
// 提交标签 |
||||
submitLabel(row, showMsg = 1) { |
||||
if (!row.labelName) return Util.errorMsg('请输入主题名称') |
||||
this.$post(`${this.api.checkLabel}?labelName=${row.labelName}&siteId=${this.site.id}&labelId=${row.id}`).then(res => { |
||||
this.$post(this.api[row.id ? 'updateLabel' : 'saveLabel'], { |
||||
labelName: row.labelName, |
||||
id: row.id, |
||||
siteId: this.site.id, |
||||
editorId: this.userId, |
||||
founderId: this.userId |
||||
}).then(res => { |
||||
showMsg && Util.successMsg((row.id ? '修改' : '新增') + '成功') |
||||
this.getLabel() |
||||
}).catch(res => {}) |
||||
}).catch(res => {}) |
||||
}, |
||||
// 关闭所属分类 |
||||
closeLabel() { |
||||
const list = this.labels |
||||
if (list.find(e => e.edit && e.labelName)) { |
||||
this.$confirm('所填写内容暂未保存,是否保存?', '提示', { |
||||
type: 'warning' |
||||
}).then(() => { |
||||
list.map(e => { |
||||
e.edit && e.labelName && this.submitLabel(e, 0) |
||||
}) |
||||
this.labelVisible = false |
||||
}).catch(() => { |
||||
this.labelVisible = false |
||||
}) |
||||
} else { |
||||
this.labelVisible = false |
||||
} |
||||
}, |
||||
|
||||
// 文章名称判重 |
||||
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 |
||||
} |
||||
}, |
||||
// 图片裁剪上传事件 |
||||
customUpload(data) { |
||||
const formData = new FormData() |
||||
formData.append('file', data, this.file.name) |
||||
this.imgUpload(formData) |
||||
}, |
||||
// 压缩图片 |
||||
compress(img) { |
||||
const canvas = document.createElement('canvas') |
||||
const ctx = canvas.getContext('2d') |
||||
// let initSize = img.src.length; |
||||
const width = img.width |
||||
const height = img.height |
||||
canvas.width = width |
||||
canvas.height = height |
||||
// 铺底色 |
||||
ctx.fillStyle = '#fff' |
||||
ctx.fillRect(0, 0, canvas.width, canvas.height) |
||||
ctx.drawImage(img, 0, 0, width, height) |
||||
// 进行压缩 |
||||
const ndata = canvas.toDataURL('image/jpeg', 0.8) |
||||
return ndata |
||||
}, |
||||
// base64转成bolb对象 |
||||
dataURItoBlob(base64Data) { |
||||
let byteString |
||||
if (base64Data.split(',')[0].indexOf('base64') >= 0) { |
||||
byteString = atob(base64Data.split(',')[1]) |
||||
} else { |
||||
byteString = unescape(base64Data.split(',')[1]) |
||||
} |
||||
const mimeString = base64Data |
||||
.split(',')[0] |
||||
.split(':')[1] |
||||
.split(';')[0] |
||||
const ia = new Uint8Array(byteString.length) |
||||
for (let i = 0; i < byteString.length; i++) { |
||||
ia[i] = byteString.charCodeAt(i) |
||||
} |
||||
return new Blob([ia], { |
||||
type: mimeString |
||||
}) |
||||
}, |
||||
// 图片上传到服务器 |
||||
imgUpload(formData) { |
||||
this.isUpload = true |
||||
Axios({ |
||||
method: 'post', |
||||
url: this.api.upload, |
||||
data: formData, |
||||
headers: { |
||||
'Content-Type': 'multipart/form-data', |
||||
token: Util.local.get(Setting.tokenKey) |
||||
}, |
||||
}).then(({ data }) => { |
||||
let url = this.form[this.isBanner ? 'bannerImg' : 'titleImg'] |
||||
url && this.$del(this.api.delFile, [url.split('/').pop()]).then(res => {}).catch(e => {}) // 删除替换掉的图片 |
||||
this.form[this.isBanner ? 'bannerImg' : 'titleImg'] = data.url |
||||
}).catch(res => {}) |
||||
this.$refs.cropper.isDisabled = false |
||||
this.isUpload = false |
||||
this.cropperModel = false |
||||
}, |
||||
// 图片改变钩子 |
||||
changeFile(file, isBanner) { |
||||
this.fixedNumber = isBanner ? [1, 0.26] : [1.76, 1] |
||||
this.isBanner = isBanner |
||||
const { size, name } = file |
||||
const ext = name.substring(name.lastIndexOf('.') + 1) |
||||
if (!Util.isImg(ext)) { |
||||
this.$message.error('请上传图片!') |
||||
return false |
||||
} |
||||
// if (size / 1024 / 1024 > 5) { |
||||
// this.$message.error('请上传5M以内的图片!') |
||||
// return false |
||||
// } |
||||
this.file = file |
||||
this.cropperModel = true |
||||
this.$nextTick(() => { |
||||
this.$refs.cropper.updateImg({ |
||||
url: window.URL.createObjectURL(file.raw), |
||||
size: file.size |
||||
}) |
||||
}) |
||||
}, |
||||
// 附件删除 |
||||
handleRemove(e, fileList) { |
||||
e.id ? this.$post(`${this.api.delContentFile}?id=${e.id}`).then(res => { |
||||
this.form.fileList = fileList |
||||
}).catch(res => {}) : (this.form.fileList = fileList) |
||||
}, |
||||
// banner上传成功 |
||||
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 |
||||
}, |
||||
// 附件上传之前的钩子 |
||||
fileBeforeUpload(file) { |
||||
this.uploading++ |
||||
}, |
||||
// 附件上传成功 |
||||
uploadSuccessFile(res) { |
||||
this.uploading-- |
||||
this.form.id ? |
||||
this.$post(this.api.saveContentFile, { |
||||
contentId: this.form.id, |
||||
editorId: this.userId, |
||||
founderId: this.userId, |
||||
id: '', |
||||
fileName: res.original, |
||||
filePath: res.url |
||||
}).then(({ data }) => { |
||||
this.form.fileList.push({ |
||||
name: res.original, |
||||
url: res.url, |
||||
id: data |
||||
}) |
||||
}).catch(res => {}) : |
||||
this.form.fileList.push({ |
||||
name: res.original, |
||||
url: res.url |
||||
}) |
||||
}, |
||||
// 预览 |
||||
preview() { |
||||
window.open((Setting.isDev ? `http://${location.hostname}:8095` : this.$store.state.content.site.domainName) + `#/article?articleId=${this.form.id}&siteId=${this.form.siteId}&id=${this.form.columnId}`) |
||||
}, |
||||
// 返回 |
||||
back() { |
||||
this.pass = true |
||||
const { updateTime } = this |
||||
// 更改了信息才需要提示 |
||||
if (updateTime > 1) { |
||||
this.$confirm(`所填写内容暂未保存,是否保存?`, '提示', { |
||||
type: 'warning' |
||||
}).then(() => { |
||||
this.submit(this.form.isRelease) |
||||
}).catch(() => { |
||||
this.$router.back() |
||||
}) |
||||
} else { |
||||
this.$router.back() |
||||
} |
||||
}, |
||||
// 更新附件的状态为发布 |
||||
updateFile(files, form, quoteId) { |
||||
files.map(e => { |
||||
this.$post(this.api.updateFile, { |
||||
id: e, |
||||
isRelease: form.isRelease, |
||||
quote: form.title, |
||||
quoteId |
||||
}).then(res => {}).catch(err => {}) |
||||
}) |
||||
}, |
||||
// 提交 |
||||
submit(isRelease, next) { |
||||
if (this.submiting) return false |
||||
const form = JSON.parse(JSON.stringify(this.form)) |
||||
if (!form.title) return Util.errorMsg('请填写标题') |
||||
if (this.nameRepeat) return Util.errorMsg('该标题已重复!') |
||||
if (typeof form.fatherId === 'object') form.fatherId = form.fatherId[form.fatherId.length - 1] |
||||
const tId = form.articleTemplate |
||||
// 如果是发布 |
||||
if (isRelease) { |
||||
if (tId !== 25) { |
||||
if (!form.releaseTime) return Util.errorMsg('请选择发布日期') |
||||
} |
||||
if (tId === 22 || tId === 23 || tId === 24) { |
||||
if (!form.titleImg ) return Util.errorMsg('请上传封面') |
||||
} |
||||
if (tId === 25) { |
||||
if ((!form.time || !form.time.length) && isRelease) return Util.errorMsg('请选择起止时间') |
||||
form.activityStartTime = form.time[0] |
||||
form.activityEndTime = form.time[1] |
||||
} |
||||
if (tId === 24 && form.connectionType !== 2) { |
||||
if (form.connectionType === 1) { |
||||
if (!this.links.length) return Util.errorMsg('请选择站内链接') |
||||
} |
||||
if (!this.otherLink.length && form.connectionType === 3) { |
||||
if (!this.otherLink.length) return Util.errorMsg('请选择栏目') |
||||
} |
||||
} |
||||
if ((tId === 22 || tId === 23 || tId === 25) && !form.mainBody) return Util.errorMsg('请输入正文') |
||||
} |
||||
if (this.uploading) return Util.errorMsg('文件正在上传,请上传完成后再发布') |
||||
if (form.connectionType === 1) { |
||||
form.linkAddress = this.links.join() |
||||
if (this.article) form.linkAddress += '-' + this.article |
||||
} else if (form.connectionType === 3) { |
||||
form.linkAddress = this.otherLink.join() |
||||
if (this.otherArticle) form.linkAddress += '-' + this.otherArticle |
||||
} |
||||
const { columnId, bannerImg, fileList, titleImg } = form |
||||
const fileId = [] |
||||
if (typeof columnId === 'object') form.columnId = columnId[columnId.length - 1] // 如果更换了栏目id,值会变成数组,需要手动获取最后一个 |
||||
// 获取几个附件的id,url后面的数字串即是附件id |
||||
if (bannerImg) fileId.push(bannerImg.substr(bannerImg.lastIndexOf('/') + 1)) |
||||
if (titleImg) fileId.push(titleImg.substr(titleImg.lastIndexOf('/') + 1)) |
||||
fileList && fileList.map(e => { |
||||
fileId.push(e[e.url ? 'url' : 'filePath'].substr(e[e.url ? 'url' : 'filePath'].lastIndexOf('/') + 1)) |
||||
}) |
||||
form.lableId = form.lableId.join(',') |
||||
|
||||
form.releaseTime = Util.formatDate('yyyy-MM-dd', new Date(form.releaseTime)) // 发布日期转化为年月日格式 |
||||
|
||||
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 => { |
||||
this.updateFile(fileId, form, form.id) |
||||
Util.successMsg('修改成功') |
||||
next ? next() : this.$router.push(`list?columnId=` + form.columnId) |
||||
}).catch(err => { |
||||
this.submiting = false |
||||
}) |
||||
} else { |
||||
this.$post(this.api.saveArticle, form).then(({ data }) => { |
||||
this.updateFile(fileId, form, data) |
||||
// 新增文章完后需要把上传的附件添加到文章附件表 |
||||
form.fileList.map(e => { |
||||
this.$post(this.api.saveContentFile, { |
||||
contentId: data, |
||||
editorId: this.userId, |
||||
founderId: this.userId, |
||||
id: '', |
||||
fileName: e.name, |
||||
filePath: e.url |
||||
}).then(res => {}).catch(err => {}) |
||||
}) |
||||
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; |
||||
flex-wrap: wrap; |
||||
width: 955px; |
||||
// height: 320px; |
||||
margin-top: 20px; |
||||
overflow: auto; |
||||
li { |
||||
margin: 0 20px 10px 0; |
||||
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; |
||||
img { |
||||
width: 80px; |
||||
} |
||||
.is-link { |
||||
width: 50px; |
||||
} |
||||
} |
||||
} |
||||
.info { |
||||
position: absolute; |
||||
top: 8px; |
||||
left: -32px; |
||||
cursor: pointer; |
||||
} |
||||
.plus { |
||||
margin-bottom: 10px; |
||||
font-size: 18px; |
||||
color: #2962FF; |
||||
text-align: right; |
||||
cursor: pointer; |
||||
} |
||||
.set-btn { |
||||
margin-left: 10px !important; |
||||
} |
||||
.manage-dia { |
||||
.edit, .del { |
||||
font-size: 14px; |
||||
cursor: pointer; |
||||
} |
||||
.edit { |
||||
margin-right: 10px; |
||||
} |
||||
} |
||||
.input-form { |
||||
&.model { |
||||
height: calc(100vh - 200px); |
||||
padding-right: 20px; |
||||
overflow: auto; |
||||
.el-form-item__label { |
||||
padding-right: 20px; |
||||
} |
||||
.lg .el-form-item__label { |
||||
padding-right: 43px; |
||||
} |
||||
} |
||||
.item-line { |
||||
display: flex; |
||||
.el-form-item:not(:last-child) { |
||||
margin-right: 200px; |
||||
} |
||||
} |
||||
.line { |
||||
margin-bottom: 24px; |
||||
border-bottom: 1px dashed #C2C2C2; |
||||
} |
||||
.el-form-item--small.el-form-item { |
||||
margin-bottom: 24px; |
||||
} |
||||
.el-input, .el-select { |
||||
width: 300px; |
||||
} |
||||
.el-select .el-input { |
||||
width: auto; |
||||
} |
||||
.el-textarea { |
||||
width: 550px; |
||||
} |
||||
.auto, .auto .el-input { |
||||
width: auto; |
||||
} |
||||
.el-form-item.is-required:not(.is-no-asterisk) > .el-form-item__label:before { |
||||
font-size: 18px; |
||||
vertical-align: -4px; |
||||
color: #F5222D; |
||||
} |
||||
} |
||||
.btns { |
||||
text-align: center; |
||||
} |
||||
</style> |
@ -0,0 +1,187 @@ |
||||
<template> |
||||
<div class="page"> |
||||
<div class="tool"> |
||||
<div class="search-wrap"> |
||||
<el-input class="keyword" placeholder="请输入标题" v-model.trim="keyword" clearable></el-input> |
||||
</div> |
||||
<div class="actions"> |
||||
<el-button v-auth="'/site/list:内容管理:文章管理:删除'" @click="batchDel">批量删除</el-button> |
||||
<el-button v-auth="'/site/list:内容管理:文章管理:新增'" type="primary" @click="add" >新增文章</el-button> |
||||
</div> |
||||
</div> |
||||
<el-table :data="list" class="table" ref="table" header-align="center" @selection-change="handleSelectionChange" row-key="id" @sort-change="sortChange"> |
||||
<el-table-column type="selection" width="55" align="center" :reserve-selection="true"></el-table-column> |
||||
<el-table-column type="index" width="60" label="序号" align="center"></el-table-column> |
||||
<el-table-column show-overflow-tooltip prop="title" label="标题" align="center" min-width="150"></el-table-column> |
||||
<el-table-column prop="classificationName" label="所属分类" align="center" min-width="120" sortable="custom"></el-table-column> |
||||
<el-table-column prop="founderName" label="录入人" align="center" min-width="80"></el-table-column> |
||||
<el-table-column prop="editorName" label="修改人" align="center" min-width="80"></el-table-column> |
||||
<el-table-column prop="updateTime" label="修改日期" align="center" min-width="150"></el-table-column> |
||||
<el-table-column prop="releaseTime" label="发布日期" align="center" min-width="100"></el-table-column> |
||||
<el-table-column prop="totalBrowsing" label="已学习人数" align="center" min-width="70"></el-table-column> |
||||
<el-table-column prop="workNumber" label="状态" align="center" min-width="80"> |
||||
<template slot-scope="scope"> |
||||
{{ scope.row.isRelease ? '已发布' : '草稿' }} |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column label="操作" align="center" width="170"> |
||||
<template slot-scope="scope"> |
||||
<el-button v-auth="'/site/list:内容管理:文章管理:编辑'" type="text" @click="edit(scope.row)">编辑</el-button> |
||||
<el-button v-auth="'/site/list:内容管理:文章管理:删除'" type="text" @click="handleDelete(scope.row)">删除</el-button> |
||||
<el-switch |
||||
class="m-l-10" |
||||
v-model="scope.row.isDisable" |
||||
:active-value="0" |
||||
:inactive-value="1" |
||||
@change="switchOff($event, scope.row, scope.$index)"> |
||||
</el-switch> |
||||
</template> |
||||
</el-table-column> |
||||
</el-table> |
||||
<div class="pagination"> |
||||
<el-pagination background @current-change="currentChange" :current-page="page" layout="total, prev, pager, next" :total="total"></el-pagination> |
||||
</div> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
import Setting from '@/setting' |
||||
import util from '@/libs/util' |
||||
import { mapMutations } from 'vuex' |
||||
export default { |
||||
data() { |
||||
return { |
||||
keyword: '', |
||||
list: [], |
||||
page: 1, |
||||
pageSize: 10, |
||||
total: 0, |
||||
modifiedTimeSort: '', |
||||
publicationTimeSort: '', |
||||
ordinalSort: 0, |
||||
multipleSelection: [], |
||||
}; |
||||
}, |
||||
watch: { |
||||
keyword: function(val) { |
||||
clearTimeout(this.searchTimer) |
||||
this.searchTimer = setTimeout(() => { |
||||
this.initData() |
||||
}, 500) |
||||
} |
||||
}, |
||||
mounted() { |
||||
// this.getData() |
||||
}, |
||||
methods: { |
||||
// 文章列表 |
||||
getData() { |
||||
const { keyword } = this |
||||
const data = { |
||||
pageNum: this.page, |
||||
pageSize: this.pageSize, |
||||
ordinalSort: this.ordinalSort, |
||||
title: this.field === 'title' ? keyword : '', |
||||
founder: this.field === 'founder' ? keyword : '', |
||||
column: this.field === 'column' ? keyword : '', |
||||
editor: this.field === 'editor' ? keyword : '' |
||||
} |
||||
if (this.modifiedTimeSort !== '') data.modifiedTimeSort = this.modifiedTimeSort |
||||
if (this.publicationTimeSort !== '') data.publicationTimeSort = this.publicationTimeSort |
||||
this.$post(this.api.queryArticle, data).then(({ data }) => { |
||||
this.list = data.records |
||||
this.total = +data.total |
||||
}).catch(err => {}) |
||||
}, |
||||
currentChange(val) { |
||||
this.page = val |
||||
this.getData() |
||||
}, |
||||
handleSelectionChange(val) { |
||||
this.multipleSelection = val |
||||
}, |
||||
initData() { |
||||
this.$refs.table.clearSelection() |
||||
this.page = 1 |
||||
this.getData() |
||||
}, |
||||
// 批量删除 |
||||
batchDel() { |
||||
const list = this.multipleSelection |
||||
if (list.length) { |
||||
this.$confirm('确定要删除吗?', '提示', { |
||||
type: 'warning' |
||||
}).then(() => { |
||||
const data = [] |
||||
list.map(e => { |
||||
data.push('ids=' + e.id) |
||||
}) |
||||
this.$post(`${this.api.deleteArticle}?${data.join('&')}`).then(res => { |
||||
this.$refs.table.clearSelection() |
||||
util.successMsg("删除成功") |
||||
this.getData() |
||||
}).catch(res => {}) |
||||
}).catch(() => {}) |
||||
} else { |
||||
util.errorMsg('请先选择数据 !') |
||||
} |
||||
}, |
||||
// 删除 |
||||
handleDelete(row) { |
||||
this.$confirm('确定要删除吗?', '提示', { |
||||
type: 'warning' |
||||
}).then(() => { |
||||
this.$post(`${this.api.deleteArticle}?ids=${row.id}`).then(res => { |
||||
util.successMsg('删除成功') |
||||
this.getData() |
||||
}).catch(res => {}) |
||||
}).catch(() => {}) |
||||
}, |
||||
// 禁用启用 |
||||
switchOff(val, row) { |
||||
this.$post(`${this.api.articleEnableOrDisable}?id=${row.id}&isDisable=${val}`).then(res => {}).catch((res) => {}) |
||||
}, |
||||
// 新增 |
||||
add() { |
||||
this.$router.push(`/learnMg`) |
||||
}, |
||||
// 排序回调 |
||||
sortChange(column) { |
||||
const { order } = column |
||||
// 三个排序只能同时传1个,所以点了一个排序的时候要清除掉其余两个 |
||||
// 两个时间0默认倒序 1升序 |
||||
if (column.prop === 'updateTime') { |
||||
this.modifiedTimeSort = order ? order === 'ascending' ? 1 : 0 : '' |
||||
if (order) { |
||||
this.publicationTimeSort = '' |
||||
this.ordinalSort = '' |
||||
} |
||||
} |
||||
if (column.prop === 'releaseTime') { |
||||
this.publicationTimeSort = order ? order === 'ascending' ? 1 : 0 : '' |
||||
if (order) { |
||||
this.modifiedTimeSort = '' |
||||
this.ordinalSort = '' |
||||
} |
||||
} |
||||
// 序号排序 0默认升序 1倒序 |
||||
if (column.prop === 'sequence') { |
||||
this.ordinalSort = order ? order === 'ascending' ? 0 : 1 : '' |
||||
if (order) { |
||||
this.publicationTimeSort = '' |
||||
this.modifiedTimeSort = '' |
||||
} |
||||
} |
||||
this.getData() |
||||
}, |
||||
// 编辑 |
||||
edit(row) { |
||||
this.$router.push(`add?id=${row.id}&columnId=${this.$refs.column.getCurrentKey()}&columnName=${this.$refs.column.getCurrentNode().columnName}`) |
||||
}, |
||||
} |
||||
}; |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
|
||||
</style> |
Loading…
Reference in new issue