合伙运维

dev_202303
yujialong 2 years ago
parent a6a1a54449
commit 9c208766b9
  1. 15
      package-lock.json
  2. 3
      package.json
  3. BIN
      src/assets/img/plus.png
  4. 11
      src/components/Sidebar.vue
  5. 235
      src/components/img-upload/Cropper.vue
  6. 535
      src/components/img-upload/index.vue
  7. 12
      src/router/index.js
  8. 4
      src/setting.js
  9. 376
      src/views/parnerOperation/editor.js
  10. 69
      src/views/parnerOperation/index.vue
  11. 967
      src/views/parnerOperation/learnMg.vue
  12. 187
      src/views/parnerOperation/mobileRole.vue
  13. 187
      src/views/parnerOperation/pcRole.vue
  14. 891
      src/views/parnerOperation/schemeSet.vue
  15. 187
      src/views/parnerOperation/staff.vue

15
package-lock.json generated

@ -6966,6 +6966,11 @@
"integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==",
"dev": true "dev": true
}, },
"image-conversion": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/image-conversion/-/image-conversion-2.1.1.tgz",
"integrity": "sha512-hnMOmP7q2jxA+52FZ+wHNhg3fdFRlgfngsQH2JQHEQkafY7tj/8F15e6Rv/RxDegc872jvyaRHwMbkTZK1Cjbg=="
},
"import-cwd": { "import-cwd": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz",
@ -12107,6 +12112,11 @@
"resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
"integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==" "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q=="
}, },
"tinymce": {
"version": "6.3.2",
"resolved": "https://registry.npmjs.org/tinymce/-/tinymce-6.3.2.tgz",
"integrity": "sha512-nOVHk4FhHKQj48hi7fEptS1Se6CNzPtfIcDzTO70KoTcSiQIFzhhZjS5bPotSzFnQ4dIQJ4QPOd7sqNs6fXUrA=="
},
"to-arraybuffer": { "to-arraybuffer": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
@ -12698,6 +12708,11 @@
"diff-match-patch": "^1.0.0" "diff-match-patch": "^1.0.0"
} }
}, },
"vue-cropper": {
"version": "0.5.10",
"resolved": "https://registry.npmjs.org/vue-cropper/-/vue-cropper-0.5.10.tgz",
"integrity": "sha512-v76nyDwMI4jvNppPlgWWpm8fQ3qVtoGZ758yLfoBRF762nJ68sjQ6z4m5Xc4d6VUbjDORm7NEduYKagxhO1MtQ=="
},
"vue-cropperjs": { "vue-cropperjs": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/vue-cropperjs/-/vue-cropperjs-3.0.0.tgz", "resolved": "https://registry.npmjs.org/vue-cropperjs/-/vue-cropperjs-3.0.0.tgz",

@ -16,13 +16,16 @@
"element-theme": "^2.0.1", "element-theme": "^2.0.1",
"element-ui": "^2.13.0", "element-ui": "^2.13.0",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"image-conversion": "^2.1.1",
"js-cookie": "^3.0.1", "js-cookie": "^3.0.1",
"mavon-editor": "^2.6.17", "mavon-editor": "^2.6.17",
"postcss-px2rem": "^0.3.0", "postcss-px2rem": "^0.3.0",
"px2rem-loader": "^0.1.9", "px2rem-loader": "^0.1.9",
"sortablejs": "^1.14.0", "sortablejs": "^1.14.0",
"tinymce": "^6.3.2",
"vue": "^2.6.10", "vue": "^2.6.10",
"vue-codemirror": "^4.0.6", "vue-codemirror": "^4.0.6",
"vue-cropper": "^0.5.10",
"vue-cropperjs": "^3.0.0", "vue-cropperjs": "^3.0.0",
"vue-pdf": "^4.3.0", "vue-pdf": "^4.3.0",
"vue-quill-editor": "^3.0.6", "vue-quill-editor": "^3.0.6",

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 B

@ -83,12 +83,12 @@ export default {
title: '数据管理' title: '数据管理'
}, },
{ {
icon: 'el-icon-box', icon: 'el-icon-tickets',
index: '/match', index: '/match',
title: '大赛管理' title: '大赛管理'
}, },
{ {
icon: 'el-icon-box', icon: 'el-icon-takeaway-box',
index: '/theoreticalCourse', index: '/theoreticalCourse',
title: '理论课程' title: '理论课程'
}, },
@ -98,7 +98,7 @@ export default {
title: '资讯管理' title: '资讯管理'
}, },
{ {
icon: 'el-icon-office-building', icon: 'el-icon-receiving',
index: '/configure', index: '/configure',
title: '服务配置' title: '服务配置'
}, },
@ -112,6 +112,11 @@ export default {
index: '/parner', index: '/parner',
title: '合伙管理' title: '合伙管理'
}, },
{
icon: 'el-icon-data-line',
index: '/parnerOperation',
title: '合伙运营'
},
], ],
menus: [], menus: [],
onRoutes: this.$route.path onRoutes: this.$route.path

@ -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
},
// base64bolb
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>

@ -217,6 +217,18 @@ let router = new Router({
component: () => import('../views/parner'), component: () => import('../views/parner'),
// meta: { title: '个人中心' } // meta: { title: '个人中心' }
}, },
{
path: '/parnerOperation',
component: () => import('../views/parnerOperation'),
},
{
path: '/learnMg',
component: () => import('../views/parnerOperation/learnMg'),
},
{
path: '/schemeSet',
component: () => import('../views/parnerOperation/schemeSet'),
},
{ {
path: '/404', path: '/404',
component: () => import('../views/404.vue'), component: () => import('../views/404.vue'),

@ -12,7 +12,7 @@ if (isDev) {
host = 'http://121.37.12.51/' host = 'http://121.37.12.51/'
// host = 'https://huorantech.cn/' // host = 'https://huorantech.cn/'
// host = 'http://192.168.31.151:9000/'// 榕 // host = 'http://192.168.31.151:9000/'// 榕
host = 'http://192.168.31.116:9000/'// 赓 // host = 'http://192.168.31.116:9000/'// 赓
} else if (isPro) { } else if (isPro) {
jumpPath = 'https://www.huorantech.cn/judgmentPoint/' jumpPath = 'https://www.huorantech.cn/judgmentPoint/'
} }
@ -45,7 +45,7 @@ const Setting = {
isDev, isDev,
isPro, isPro,
// 是否使用动态路由 // 是否使用动态路由
dynamicRoute: true, dynamicRoute: false,
/** /**
* @description 默认密码 * @description 默认密码
*/ */

@ -0,0 +1,376 @@
import Axios from 'axios'
import Api from '@/utils/api'
import Setting from '@/setting'
import Util from '@/libs/util'
export default {
//skin:'oxide-dark',
language:'zh_CN',
language_url: './styles/tinymce/langs/zh_CN.js',
plugins: 'print powerpaste preview searchreplace autolink directionality visualblocks visualchars fullscreen image link media template advcode codesample table charmap hr pagebreak nonbreaking anchor insertdatetime advlist lists wordcount imagetools textpattern help emoticons autosave autoresize formatpainter',
toolbar: 'code undo redo restoredraft | cut copy powerpaste pastetext | forecolor backcolor headings fontsize lineHeight bold italic underline strikethrough link anchor | alignleft aligncenter alignright alignjustify | \
styleselect fontselect fontsizeselect | bullist numlist | blockquote subscript superscript removeformat | \
table image media charmap emoticons hr pagebreak insertdatetime print preview | fullscreen | indent2em formatpainter',
style_formats: [
//新增 首行缩进与行高 配置
{
title: '首行缩进',
block: 'p',
styles: {
'text-indent': '2em'
}
},
{
title: '行高',
items: [{
title: '1',
styles: {
'line-height': '1'
},
inline: 'span'
},
{
title: '1.5',
styles: {
'line-height': '1.5'
},
inline: 'span'
},
{
title: '2',
styles: {
'line-height': '2'
},
inline: 'span'
},
{
title: '2.5',
styles: {
'line-height': '2.5'
},
inline: 'span'
},
{
title: '3',
styles: {
'line-height': '3'
},
inline: 'span'
}
]
},
//默认的配置
{
title: 'headings',
items: [
{
title: 'Heading 1',
format: 'h1'
},
{
title: 'Heading 2',
format: 'h2'
},
{
title: 'Heading 3',
format: 'h3'
},
{
title: 'Heading 4',
format: 'h4'
},
{
title: 'Heading 5',
format: 'h5'
},
{
title: 'Heading 6',
format: 'h6'
}
]
},
{
title: 'Inline',
items: [
{
title: 'Bold',
icon: 'bold',
format: 'bold'
},
{
title: 'Italic',
icon: 'italic',
format: 'italic'
},
{
title: 'Underline',
icon: 'underline',
format: 'underline'
},
{
title: 'Strikethrough',
icon: 'strikethrough',
format: 'strikethrough'
},
{
title: 'Superscript',
icon: 'superscript',
format: 'superscript'
},
{
title: 'Subscript',
icon: 'subscript',
format: 'subscript'
},
{
title: 'Code',
icon: 'code',
format: 'code'
}
]
},
{
title: 'Blocks',
items: [
{
title: 'Paragraph',
format: 'p'
},
{
title: 'Blockquote',
format: 'blockquote'
},
{
title: 'Div',
format: 'div'
},
{
title: 'Pre',
format: 'pre'
}
]
},
{
title: 'Alignment',
items: [
{
title: 'Left',
icon: 'alignleft',
format: 'alignleft'
},
{
title: 'Center',
icon: 'aligncenter',
format: 'aligncenter'
},
{
title: 'Right',
icon: 'alignright',
format: 'alignright'
},
{
title: 'Justify',
icon: 'alignjustify',
format: 'alignjustify'
}
]
}
],
promotion: false,
branding: false,
width: 940,
height: 650, //编辑器高度
min_height: 400,
content_css: [ //可设置编辑区内容展示的css,谨慎使用
'./styles/css/editor.css',
],
// content_style: Style,
fontsize_formats: '12px 14px 16px 19px 24px 36px 48px 56px 72px',
font_formats: '苹果苹方=PingFang SC,Microsoft YaHei,sans-serif;宋体=simsun,serif;微软雅黑=Microsoft YaHei,Helvetica Neue,PingFang SC,sans-serif;仿宋体=FangSong,serif;黑体=SimHei,sans-serif;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier;Georgia=georgia,palatino;Helvetica=helvetica;Impact=impact,chicago;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco;Times New Roman=times new roman,times;Verdana=verdana,geneva;Webdings=webdings;Wingdings=wingdings,zapf dingbats;知乎配置=BlinkMacSystemFont, Helvetica Neue, PingFang SC, Microsoft YaHei, Source Han Sans SC, Noto Sans CJK SC, WenQuanYi Micro Hei, sans-serif;小米配置=Helvetica Neue,Helvetica,Arial,Microsoft Yahei,Hiragino Sans GB,Heiti SC,WenQuanYi Micro Hei,sans-serif',
link_list: [
{ title: '预置链接1', value: 'http://www.tinymce.com' },
{ title: '预置链接2', value: 'http://tinymce.ax-z.cn' }
],
image_list: [
{ title: '预置图片1', value: 'https://www.tiny.cloud/images/glyph-tinymce@2x.png' },
{ title: '预置图片2', value: 'https://www.baidu.com/img/bd_logo1.png' }
],
image_class_list: [
{ title: 'None', value: '' },
{ title: 'Some class', value: 'class-name' }
],
//importcss_append: true,
//自定义文件选择器的回调内容
file_picker_callback: function (callback, value, meta) {
if (meta.filetype === 'file') {
callback('https://www.baidu.com/img/bd_logo1.png', { text: 'My text' });
}
if (meta.filetype === 'image') {
callback('https://www.baidu.com/img/bd_logo1.png', { alt: 'My alt text' });
}
if (meta.filetype === 'media') {
callback('movie.mp4', { source2: 'alt.ogg', poster: 'https://www.baidu.com/img/bd_logo1.png' });
}
},
//为内容模板插件提供预置模板
templates: [
{ title: '中文文章模板1', description: '图片文字流', content: `
<div class="tiny-wrap">
<div class="block">
<div class="fl">
<img class="pic" src="images/default.png"/>
<p class="img-des">图片描述</p>
</div>
<div class="texts">
<p>S³FEL主要由一台超导直线加速器波荡器光束线和实验站组成可产生重复频率达1MHz电子束能量达2.5 GeV的软X 射线自由电子激光可在百飞秒内级实现原子分子及外壳层电子结构的无损动态监测是科学家认识和了解物质微观结构及动态变化的高速摄像机S³FEL为科学家和企业用户提供了一种具有超高时间分辨空间分辨和能量分辨的新方法新技术 S³FEL在量子材料能源催化生物医药大气与星际科学原子分子科学等领域的应用研究将为促进我国战略性新兴产业创新发展和关键S³FEL主要由一台超导直线加速器波荡器光束线和实验站组成可产生重复频率达1MHz电子束能量达2.5 GeV的软X 射线自由电子激光可在百飞秒内级实现原子分子及外壳层电子结构的无损动态监测是科学家认识和了解物质微观结构及动态变化的高速摄像机S³FEL为科学家和企业用户提供了一种具有超高时间分辨空间分辨和能量分辨的新方法新技术 S³FEL在量子材料能源催化生物医药大气与星际科学原子分子科学等领域的应用研究将为促进我国战略性新兴产业创新发展和关键S³FEL主要由一台超导直线加速器波荡器光束线和实验站组成可产生重复频率达1MHz电子束能量达2.5 GeV的软X 射线自由电子激光可在百飞秒内级实现原子分子及外壳层电子结构的无损动态监测是科学家认识和了解物质微观结构及动态变化的高速摄像机S³FEL为科学家和企业用户提供了一种具有超高时间分辨空间分辨和能量分辨的新方法新技术 S³FEL在量子材料能源催化生物医药大气与星际科学原子分子科学等领域的应用研究将为促进我国战略性新兴产业创新发展和关键S³FEL主要由一台超导直线加速器波荡器光束线和实验站组成可产生重复频率达1MHz电子束能量达2.5 GeV的软X 射线自由电子激光可在百飞秒内级实现原子分子及外壳层电子结构的无损动态监测是科学家认识和了解物质微观结构及动态变化的高速摄像机S³FEL在量子材料能源催化生物医药大气与星际科学原子分子科学等领域的应用研究将为促进我国战略性新兴产业创新发展和关键S³FEL主要由一台超导直线加速器波荡器光束线和实验站组成可产生重复频率达1MHz电子束能量达2.5 GeV的软X 射线自由电子激光可在百飞秒内级实现原子分子及外壳层电子结构的无损动态监测是科学家认识和了解物质微观结构及动态变化的高速摄像机
</p>
</div>
</div>
<div class="block">
<div class="fr">
<img class="pic" src="images/default.png"/>
<p class="img-des">图片描述</p>
</div>
<div>
<p>集聚世界前沿和原创性科学技术及产业研发将推动一批高水平大学和科研机构的科技人才队伍建设及相关学科的高质量发展营造粤港澳大湾区人才高地并助力粤港澳大湾区国际科技创新中心的建设此外 S³FEL作为重要的科普教育基地</p>
<p>S³FEL汇聚并培养信息生命材料能源等学科领域的国际水平科技领军人才集聚世界前沿和原创性科学技术及产业研发将推动一批高水平大学和科研机构的科技人才队伍建设及相关学科的高质量发展营造粤港澳大湾区人才高地并助力粤港澳大湾区国际科技创新中心的建设此外 S³FEL作为重要的科普教育基地是展示我国科技实力提高全民族科学素质和民族自信的重要宣传窗口 S³FEL主体建筑将成为深圳市地标式建筑促进提升深圳市的城市形象和国际化知名度S³FEL汇聚并培养信息生命材料能源等学科领域的国际水平科技领军人才集聚世界前沿和原创性科学技术及产业研发将推动一批高水平大学和科研机构的科技人才队伍建设及相关学科的高质量发展营造粤港澳大湾区人才高地并助力粤港澳大湾区国际科技创新中心的建设此外 S³FEL作为重要的科普教育基地是展示我国科技实力提高全民族科学素质和民族自信的重要宣传窗口 S³FEL主体建筑将成为深圳市地标式建筑促进提升深圳市的城市形象和国际化知名度S³FEL汇聚并培养信息生命材料能源等学科领域的国际水平科技领军人才集聚世界前沿和原创性科学技术及产业研发将推动一批高水平大学和科研机构的科技人才队伍建设及相关学科的高质量发展营造粤港澳大湾区人才高地并助力粤港澳大湾区国际科技创新中心的建设此外 S³FEL作为重要的科普教育基地是展示我国科技实力提高全民族科学素质和民族自信的重要宣传窗口 S³FEL主体建筑将成为深圳市地标式建筑促进提升深圳市的城市形象和国际化知名度</p>
</div>
</div>
</div>
`
},
{ title: '英文文章模板1', description: '图片文字流', content: `
<div class="tiny-wrap">
<div class="block en-block">
<div class="fr">
<img class="pic" src="images/default.png"/>
<p class="img-des">Picture description</p>
</div>
<div>
<p>One of the major barriers to treating pain effectively is rooted in providers fear of killing their patients. This includes caregivers who may be family or friends. In a 2014 study I led of nonprofessional hospice caregivers, we found that the majority of pain medication errors caregivers made involved administering less than the prescribed dose, which makes it difficult for patients to achieve optimal pain relief.</p>
<p>Meanwhile, more than 11 million Americans  often family members or friends provide unpaid care for people with Alzheimer's or other dementias, according to calculations by the Alzheimers Association. In 2021, caregivers for people with Alzheimers or other dementias provided an estimated 16 billion hours of unpaid care valued at nearly $272 billion.My father took her to the emergency room. A doctor found a severe knee infection and took her into surgery. She was hospitalized for two weeks, followed by two months of rehabilitation at a skilled nursing facility.</p>
<p>If you heated the salt on your kitchen table up to 801 C (1,474 F), it would melt, and youd have molten salt. However, for making and storing energy, not just any salt will do. Scientists are exploring different combinations of salts to get the exact properties needed to cool and fuel a nuclear power reactor efficiently for decades. These properties include lower melting temperatures, the right consistency, and the ability to absorb high amounts of heat, among others.</p>
<div class="quote">We used experimental results to validate our simulation. At the same time, the simulation results provided us more details about which salts to study further. They work with each other. Jicheng Guo, chemical engineer at Argonne National Laboratory</div>
<p>Which molten salt blueprints will deliver the desired traits for a nuclear reactor? The potential variations are nearly endless. The study set out to determine whether computer simulations driven by machine learning could guide and refine real-world experiments at the Advanced Photon Source (APS), a DOE Office of Science user facility at Argonne. The results were recently published in the journal Physical Review B.</p>
<p>We used experimental results from the APS to validate our simulation. At the same time, the simulation results provided us more details about which salts to study further. They work with each other, said Jicheng Guo, a chemical engineer at Argonne and the papers lead author. This allows us to study multiple compositions at the same time.</p>
</div>
</div>
</div>
`
},
{ title: '新闻模板', description: '', content: `
<div class="tiny-wrap">
<div class="block" style="margin-bottom: 70px;">
<div class="fr">
<img class="pic" src="images/default.png"/>
<p class="img-des">图片描述</p>
</div>
<div>
<p style="text-indent: 2em">S³FEL汇聚并培养信息生命材料能源等学科领域的国际水平科技领军人才集聚世界前沿和原创性科学技术及产业研发将推动一批高水平大学和科研机构的科技人才队伍建设及相关学科的高质量发展营造粤港澳大湾区人才高地并助力粤港澳大湾区国际科技创新中心的建设此外 S³FEL作为重要的科普教育基地是展示我国科技实力提高全民族科学素质和民族自信的重要宣传窗口 S³FEL主体建筑将成为深圳市地标式建筑促进提升深圳市的城市形象和国际化知名度S³FEL汇聚并培养信息生命材料能源等学科领域的国际水平科技领军人才集聚世界前沿和原创性科学技术及产业研发将推动一批高水平大学和科研机构的科技人才队伍建设及相关学科的高质量发展营造粤港澳大湾区人才高地并助力粤港澳大湾区国际科技创新中心的建设此外 S³FEL作为重要的科普教育基地是展示我国科技实力提高全民族科学素质和民族自信的重要宣传窗口 S³FEL主体建筑将成为深圳市地标式建筑促进提升深圳市的城市形象和国际化知名度S³FEL汇聚并培养信息生命材料能源等学科领域的国际水平科技领军人才集聚世界前沿和原创性科学技术及产业研发将推动一批高水平大学和科研机构的科技人才队伍建设及相关学科的高质量发展营造粤港澳大湾区人才高地并助力粤港澳大湾区国际科技创新中心的建设此外 S³FEL作为重要的科普教育基地是展示我国科技实力提高全民族科学素质和民族自信的重要宣传窗口 S³FEL主体建筑将成为深圳市地标式建筑促进提升深圳市的城市形象和国际化知名度</p>
<div class="quote">
Here is a long quotation here is a long quotation here is a long quotation
here is a long quotation here is a long quotation here is a long quotation
here is a long quotation here is a long quotation here is a long quotation.
</div>
</div>
</div>
<div class="block">
<div class="img-wrap">
<img class="pic" src="images/default.png"/>
<p class="img-des">图片描述</p>
</div>
<div class="texts">
<h6 class="tiny-title">小标题</h6>
<p style="text-indent: 2em">S³FEL主要由一台超导直线加速器波荡器光束线和实验站组成可产生重复频率达1MHz电子束能量达2.5 GeV的软X 射线自由电子激光可在百飞秒内级实现原子分子及外壳层电子结构的无损动态监测是科学家认识和了解物质微观结构及动态变化的高速摄像机S³FEL为科学家和企业用户提供了一种具有超高时间分辨空间分辨和能量分辨的新方法新技术 S³FEL在量子材料能源催化生物医药大气与星际科学原子分子科学等领域的应用研究将为促进我国战略性新兴产业创新发展和关键S³FEL主要由一台超导直线加速器波荡器光束线和实验站组成可产生重复频率达1MHz电子束能量达2.5 GeV的软X 射线自由电子激光可在百飞秒内级实现原子分子及外壳层电子结构的无损动态监测是科学家认识和了解物质微观结构及动态变化的高速摄像机S³FEL为科学家和企业用户提供了一种具有超高时间分辨空间分辨和能量分辨的新方法新技术 S³FEL在量子材料能源催化生物医药大气与星际科学原子分子科学等领域的应用研究将为促进我国战略性新兴产业创新发展和关键
</p>
</div>
</div>
</div>
`
},
{ title: '图片描述', description: '', content: `
<div class="tiny-wrap">
<div class="block">
<div class="img-wrap">
<img class="pic" src="images/default.png"/>
<p class="img-des">图片描述</p>
</div>
</div>
</div>
`
}
],
// content_security_policy: "https://cdn.tiny.cloud/1/rnk6zw9v267xqz7pf98twt1vmrvltmd436je7a642pckltda/tinymce/6/tinymce.min.js",
// extended_valid_elements:'script[src]',
//
// template_cdate_format: '[CDATE: %m/%d/%Y : %H:%M:%S]',
// template_mdate_format: '[MDATE: %m/%d/%Y : %H:%M:%S]',
// autosave_ask_before_unload: false,
toolbar_mode : 'wrap',
// automatic_uploads: true,
// images_upload_base_path: '/demo',
// images_upload_url: 'http://10.10.11.7:10000/iasf/sysFiles/upload',
paste_data_images: true,
powerpaste_allow_local_images: true,
powerpaste_word_import: 'clean',
powerpaste_html_import: 'clean',
// 自定义上传
images_upload_handler: function (blobInfo, succFun, failFun) {
const form = new FormData()
form.append('file', blobInfo.blob()),
Axios({
method: 'post',
url: Api.upload,
data: form,
headers: {
'Content-Type': 'multipart/form-data',
token: Util.local.get(Setting.tokenKey)
},
}).then(({ data }) => {
succFun(data.url)
}).catch(res => {})
},
//自定义文件选择器的回调内容 此方法只有在点击上方图片按钮才会触发
file_picker_callback: function (callback, value, meta) {
if (meta.filetype === 'file') {
callback('https://www.baidu.com/img/bd_logo1.png', { text: 'My text' });
}
if (meta.filetype === 'image') {
callback('https://www.baidu.com/img/bd_logo1.png', { alt: 'My alt text' });
}
// 主要判断 media
if (meta.filetype === 'media') {
// 动态创建上传input,并进行模拟点击上传操作,达到本地上传视频效果。
let input = document.createElement('input');//创建一个隐藏的input
input.setAttribute('type', 'file');
input.setAttribute("accept", ".mp4");
input.onchange = function(){
let file = this.files[0];
let fd = new FormData();
fd.append("file", file);
Axios({
method: 'post',
url: Api.upload,
data: fd,
headers: {
'Content-Type': 'multipart/form-data',
token: Util.local.get(Setting.tokenKey)
},
}).then(({ data }) => {
callback(data.url)
}).catch(res => {})
}
//触发点击
input.click();
}
},
// 初始化事件
setup: function(editor) {
editor.on('init', function(ed) {
// 设置默认字体
ed.target.editorCommands.execCommand("fontName", false, "Microsoft Yahei")
ed.target.editorCommands.execCommand("fontSize", false, "19px")
ed.target.editorCommands.execCommand("lineHeight", false, "1.5")
top.document.querySelector('#articleTitle').focus() // 第一个字段聚焦
})
},
}

@ -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
},
// base64bolb
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
// idurlid
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
},
// base64bolb
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
// idurlid
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…
Cancel
Save