article
This commit is contained in:
parent
9c7f4023eb
commit
48c4edb7ea
|
@ -875,6 +875,75 @@
|
|||
"to-fast-properties": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"@ckeditor/ckeditor5-build-classic": {
|
||||
"version": "18.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-build-classic/-/ckeditor5-build-classic-18.0.0.tgz",
|
||||
"integrity": "sha512-7nyaDU5sUSl+7wXPwr0d5bOlO2e0LRQh2iJJCJfAjjuUESwtiBGoFC+Ql5dEht0xlfARoSWQMlkUvGuHOVja7A=="
|
||||
},
|
||||
"@ckeditor/ckeditor5-core": {
|
||||
"version": "18.0.0",
|
||||
"resolved": "https://registry.npm.taobao.org/@ckeditor/ckeditor5-core/download/@ckeditor/ckeditor5-core-18.0.0.tgz",
|
||||
"integrity": "sha1-71NcvrPEgY1GPkXnhEY/k3vy1js=",
|
||||
"requires": {
|
||||
"@ckeditor/ckeditor5-engine": "^18.0.0",
|
||||
"@ckeditor/ckeditor5-utils": "^18.0.0",
|
||||
"lodash-es": "^4.17.10"
|
||||
}
|
||||
},
|
||||
"@ckeditor/ckeditor5-editor-classic": {
|
||||
"version": "18.0.0",
|
||||
"resolved": "https://registry.npm.taobao.org/@ckeditor/ckeditor5-editor-classic/download/@ckeditor/ckeditor5-editor-classic-18.0.0.tgz",
|
||||
"integrity": "sha1-YquzsVFShohUzoJJ/8MKRT8k/ek=",
|
||||
"requires": {
|
||||
"@ckeditor/ckeditor5-core": "^18.0.0",
|
||||
"@ckeditor/ckeditor5-engine": "^18.0.0",
|
||||
"@ckeditor/ckeditor5-ui": "^18.0.0",
|
||||
"@ckeditor/ckeditor5-utils": "^18.0.0",
|
||||
"lodash-es": "^4.17.10"
|
||||
}
|
||||
},
|
||||
"@ckeditor/ckeditor5-engine": {
|
||||
"version": "18.0.0",
|
||||
"resolved": "https://registry.npm.taobao.org/@ckeditor/ckeditor5-engine/download/@ckeditor/ckeditor5-engine-18.0.0.tgz",
|
||||
"integrity": "sha1-iKtK8/zggGuQ/drZjJDRYkFlst4=",
|
||||
"requires": {
|
||||
"@ckeditor/ckeditor5-utils": "^18.0.0",
|
||||
"lodash-es": "^4.17.10"
|
||||
}
|
||||
},
|
||||
"@ckeditor/ckeditor5-ui": {
|
||||
"version": "18.0.0",
|
||||
"resolved": "https://registry.npm.taobao.org/@ckeditor/ckeditor5-ui/download/@ckeditor/ckeditor5-ui-18.0.0.tgz",
|
||||
"integrity": "sha1-GSlSk6IwAR3tU/5OYgQFppwMsRU=",
|
||||
"requires": {
|
||||
"@ckeditor/ckeditor5-core": "^18.0.0",
|
||||
"@ckeditor/ckeditor5-utils": "^18.0.0",
|
||||
"lodash-es": "^4.17.10"
|
||||
}
|
||||
},
|
||||
"@ckeditor/ckeditor5-upload": {
|
||||
"version": "18.0.0",
|
||||
"resolved": "https://registry.npm.taobao.org/@ckeditor/ckeditor5-upload/download/@ckeditor/ckeditor5-upload-18.0.0.tgz",
|
||||
"integrity": "sha1-ay1FTh3+rcKQQW7UrkJNGGQktfo=",
|
||||
"requires": {
|
||||
"@ckeditor/ckeditor5-core": "^18.0.0",
|
||||
"@ckeditor/ckeditor5-ui": "^18.0.0",
|
||||
"@ckeditor/ckeditor5-utils": "^18.0.0"
|
||||
}
|
||||
},
|
||||
"@ckeditor/ckeditor5-utils": {
|
||||
"version": "18.0.0",
|
||||
"resolved": "https://registry.npm.taobao.org/@ckeditor/ckeditor5-utils/download/@ckeditor/ckeditor5-utils-18.0.0.tgz",
|
||||
"integrity": "sha1-lc1mYcAA6RV+u3BSoUKp2qNLU4g=",
|
||||
"requires": {
|
||||
"lodash-es": "^4.17.10"
|
||||
}
|
||||
},
|
||||
"@ckeditor/ckeditor5-vue": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-vue/-/ckeditor5-vue-1.0.1.tgz",
|
||||
"integrity": "sha512-4MaQwZ04cWwqYW0732sg2aqx9ILeHIP0LSLKUuLCLR21qYONZPvxY/V/czh1DH99toaL/iwPvEoJtO2ldriPaA=="
|
||||
},
|
||||
"@hapi/address": {
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npm.taobao.org/@hapi/address/download/@hapi/address-2.1.4.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40hapi%2Faddress%2Fdownload%2F%40hapi%2Faddress-2.1.4.tgz",
|
||||
|
@ -9793,7 +9862,7 @@
|
|||
},
|
||||
"load-script": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npm.taobao.org/load-script/download/load-script-1.0.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/load-script/-/load-script-1.0.0.tgz",
|
||||
"integrity": "sha1-BJGTngvuVkPuSUp+PaPSuscMbKQ="
|
||||
},
|
||||
"loader-fs-cache": {
|
||||
|
@ -9897,6 +9966,11 @@
|
|||
"integrity": "sha1-tEf2ZwoEVbv+7dETku/zMOoJdUg=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash-es": {
|
||||
"version": "4.17.15",
|
||||
"resolved": "https://registry.npm.taobao.org/lodash-es/download/lodash-es-4.17.15.tgz",
|
||||
"integrity": "sha1-Ib2Wg5NUQS8j16EDQOXqxu5FXXg="
|
||||
},
|
||||
"lodash.defaultsdeep": {
|
||||
"version": "4.6.1",
|
||||
"resolved": "https://registry.npm.taobao.org/lodash.defaultsdeep/download/lodash.defaultsdeep-4.6.1.tgz?cache=0&sync_timestamp=1562718178896&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash.defaultsdeep%2Fdownload%2Flodash.defaultsdeep-4.6.1.tgz",
|
||||
|
|
|
@ -15,6 +15,10 @@
|
|||
"svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ckeditor/ckeditor5-build-classic": "^18.0.0",
|
||||
"@ckeditor/ckeditor5-editor-classic": "^18.0.0",
|
||||
"@ckeditor/ckeditor5-upload": "^18.0.0",
|
||||
"@ckeditor/ckeditor5-vue": "^1.0.1",
|
||||
"axios": "0.18.1",
|
||||
"ckeditor4-vue": "^0.2.0",
|
||||
"echarts": "^4.7.0",
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
import request from '@/utils/request'
|
||||
|
||||
export function getArticleList() {
|
||||
return request({
|
||||
url: '/cms/article/',
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
export function createArticle(data) {
|
||||
return request({
|
||||
url: '/cms/article/',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
export function updateArticle(id, data) {
|
||||
return request({
|
||||
url: `/cms/article/${id}/`,
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
export function deleteArticle(id) {
|
||||
return request({
|
||||
url: `/cms/article/${id}/`,
|
||||
method: 'delete',
|
||||
})
|
||||
}
|
||||
export function getArticle(id) {
|
||||
return request({
|
||||
url: `/cms/article/${id}/`,
|
||||
method: 'get',
|
||||
})
|
||||
}
|
|
@ -1,9 +1,6 @@
|
|||
<template>
|
||||
<div :class="{fullscreen:fullscreen}" class="tinymce-container" :style="{width:containerWidth}">
|
||||
<textarea :id="tinymceId" class="tinymce-textarea" />
|
||||
<div class="editor-custom-btn-container">
|
||||
<editorImage color="#1890ff" class="editor-upload-btn" @successCBK="imageSuccessCBK" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -12,38 +9,42 @@
|
|||
* docs:
|
||||
* https://panjiachen.github.io/vue-element-admin-site/feature/component/rich-editor.html#tinymce
|
||||
*/
|
||||
import editorImage from './components/EditorImage'
|
||||
import plugins from './plugins'
|
||||
import toolbar from './toolbar'
|
||||
import load from './dynamicLoadScript'
|
||||
|
||||
import plugins from "./plugins";
|
||||
import toolbar from "./toolbar";
|
||||
import load from "./dynamicLoadScript";
|
||||
import { uploadUrl, myHeaders } from "@/api/file";
|
||||
import { getToken } from "@/utils/auth";
|
||||
// why use this cdn, detail see https://github.com/PanJiaChen/tinymce-all-in-one
|
||||
const tinymceCDN = 'https://cdn.jsdelivr.net/npm/tinymce-all-in-one@4.9.3/tinymce.min.js'
|
||||
const tinymceCDN =
|
||||
"https://cdn.jsdelivr.net/npm/tinymce-all-in-one@4.9.3/tinymce.min.js";
|
||||
|
||||
export default {
|
||||
name: 'Tinymce',
|
||||
components: { editorImage },
|
||||
name: "Tinymce",
|
||||
props: {
|
||||
id: {
|
||||
type: String,
|
||||
default: function() {
|
||||
return 'vue-tinymce-' + +new Date() + ((Math.random() * 1000).toFixed(0) + '')
|
||||
return (
|
||||
"vue-tinymce-" +
|
||||
+new Date() +
|
||||
((Math.random() * 1000).toFixed(0) + "")
|
||||
);
|
||||
}
|
||||
},
|
||||
value: {
|
||||
type: String,
|
||||
default: ''
|
||||
default: ""
|
||||
},
|
||||
toolbar: {
|
||||
type: Array,
|
||||
required: false,
|
||||
default() {
|
||||
return []
|
||||
return [];
|
||||
}
|
||||
},
|
||||
menubar: {
|
||||
type: String,
|
||||
default: 'file edit insert view format table'
|
||||
default: "file edit insert view format table"
|
||||
},
|
||||
height: {
|
||||
type: [Number, String],
|
||||
|
@ -53,7 +54,7 @@ export default {
|
|||
width: {
|
||||
type: [Number, String],
|
||||
required: false,
|
||||
default: 'auto'
|
||||
default: "auto"
|
||||
}
|
||||
},
|
||||
data() {
|
||||
|
@ -63,91 +64,93 @@ export default {
|
|||
tinymceId: this.id,
|
||||
fullscreen: false,
|
||||
languageTypeList: {
|
||||
'en': 'en',
|
||||
'zh': 'zh_CN',
|
||||
'es': 'es_MX',
|
||||
'ja': 'ja'
|
||||
en: "en",
|
||||
zh: "zh_CN",
|
||||
es: "es_MX",
|
||||
ja: "ja"
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
containerWidth() {
|
||||
const width = this.width
|
||||
if (/^[\d]+(\.[\d]+)?$/.test(width)) { // matches `100`, `'100'`
|
||||
return `${width}px`
|
||||
const width = this.width;
|
||||
if (/^[\d]+(\.[\d]+)?$/.test(width)) {
|
||||
// matches `100`, `'100'`
|
||||
return `${width}px`;
|
||||
}
|
||||
return width
|
||||
return width;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value(val) {
|
||||
if (!this.hasChange && this.hasInit) {
|
||||
this.$nextTick(() =>
|
||||
window.tinymce.get(this.tinymceId).setContent(val || ''))
|
||||
window.tinymce.get(this.tinymceId).setContent(val || "")
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.init()
|
||||
this.init();
|
||||
},
|
||||
activated() {
|
||||
if (window.tinymce) {
|
||||
this.initTinymce()
|
||||
this.initTinymce();
|
||||
}
|
||||
},
|
||||
deactivated() {
|
||||
this.destroyTinymce()
|
||||
this.destroyTinymce();
|
||||
},
|
||||
destroyed() {
|
||||
this.destroyTinymce()
|
||||
this.destroyTinymce();
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
// dynamic load tinymce from cdn
|
||||
load(tinymceCDN, (err) => {
|
||||
load(tinymceCDN, err => {
|
||||
if (err) {
|
||||
this.$message.error(err.message)
|
||||
return
|
||||
this.$message.error(err.message);
|
||||
return;
|
||||
}
|
||||
this.initTinymce()
|
||||
})
|
||||
this.initTinymce();
|
||||
});
|
||||
},
|
||||
initTinymce() {
|
||||
const _this = this
|
||||
const _this = this;
|
||||
window.tinymce.init({
|
||||
selector: `#${this.tinymceId}`,
|
||||
language: this.languageTypeList['en'],
|
||||
language: this.languageTypeList["zh"],
|
||||
height: this.height,
|
||||
body_class: 'panel-body ',
|
||||
body_class: "panel-body ",
|
||||
object_resizing: false,
|
||||
toolbar: this.toolbar.length > 0 ? this.toolbar : toolbar,
|
||||
menubar: this.menubar,
|
||||
plugins: plugins,
|
||||
end_container_on_empty_block: true,
|
||||
powerpaste_word_import: 'clean',
|
||||
powerpaste_word_import: "clean",
|
||||
code_dialog_height: 450,
|
||||
code_dialog_width: 1000,
|
||||
advlist_bullet_styles: 'square',
|
||||
advlist_number_styles: 'default',
|
||||
imagetools_cors_hosts: ['www.tinymce.com', 'codepen.io'],
|
||||
default_link_target: '_blank',
|
||||
advlist_bullet_styles: "square",
|
||||
advlist_number_styles: "default",
|
||||
imagetools_cors_hosts: ["www.tinymce.com", "codepen.io"],
|
||||
default_link_target: "_blank",
|
||||
link_title: false,
|
||||
nonbreaking_force_tab: true, // inserting nonbreaking space need Nonbreaking Space Plugin
|
||||
init_instance_callback: editor => {
|
||||
if (_this.value) {
|
||||
editor.setContent(_this.value)
|
||||
editor.setContent(_this.value);
|
||||
}
|
||||
_this.hasInit = true
|
||||
editor.on('NodeChange Change KeyUp SetContent', () => {
|
||||
this.hasChange = true
|
||||
this.$emit('input', editor.getContent())
|
||||
})
|
||||
_this.hasInit = true;
|
||||
editor.on("NodeChange Change KeyUp SetContent", () => {
|
||||
this.hasChange = true;
|
||||
this.$emit("input", editor.getContent());
|
||||
});
|
||||
},
|
||||
setup(editor) {
|
||||
editor.on('FullscreenStateChanged', (e) => {
|
||||
_this.fullscreen = e.state
|
||||
})
|
||||
}
|
||||
editor.on("FullscreenStateChanged", e => {
|
||||
_this.fullscreen = e.state;
|
||||
});
|
||||
},
|
||||
// 整合七牛上传
|
||||
// images_dataimg_filter(img) {
|
||||
// setTimeout(() => {
|
||||
|
@ -163,50 +166,54 @@ export default {
|
|||
// }, 0);
|
||||
// return img
|
||||
// },
|
||||
// images_upload_handler(blobInfo, success, failure, progress) {
|
||||
// progress(0);
|
||||
// const token = _this.$store.getters.token;
|
||||
// getToken(token).then(response => {
|
||||
// const url = response.data.qiniu_url;
|
||||
// const formData = new FormData();
|
||||
// formData.append('token', response.data.qiniu_token);
|
||||
// formData.append('key', response.data.qiniu_key);
|
||||
// formData.append('file', blobInfo.blob(), url);
|
||||
// upload(formData).then(() => {
|
||||
// success(url);
|
||||
// progress(100);
|
||||
// })
|
||||
// }).catch(err => {
|
||||
// failure('出现未知问题,刷新页面,或者联系程序员')
|
||||
// console.log(err);
|
||||
// });
|
||||
// },
|
||||
})
|
||||
images_upload_handler: function(blobInfo, succFun, failFun) {
|
||||
var xhr, formData;
|
||||
var file = blobInfo.blob(); //转化为易于理解的file对象
|
||||
xhr = new XMLHttpRequest();
|
||||
xhr.withCredentials = false;
|
||||
xhr.open("POST", uploadUrl());
|
||||
xhr.setRequestHeader('Authorization', 'JWT '+ getToken());
|
||||
xhr.onload = function() {
|
||||
var json;
|
||||
if (xhr.status != 200) {
|
||||
failFun("HTTP Error: " + xhr.status);
|
||||
return;
|
||||
}
|
||||
json = JSON.parse(xhr.responseText);
|
||||
succFun(json.data.path);
|
||||
};
|
||||
formData = new FormData();
|
||||
formData.append("file", file, file.name); //此处与源文档不一样
|
||||
xhr.send(formData);
|
||||
}
|
||||
});
|
||||
},
|
||||
destroyTinymce() {
|
||||
const tinymce = window.tinymce.get(this.tinymceId)
|
||||
const tinymce = window.tinymce.get(this.tinymceId);
|
||||
if (this.fullscreen) {
|
||||
tinymce.execCommand('mceFullScreen')
|
||||
tinymce.execCommand("mceFullScreen");
|
||||
}
|
||||
|
||||
if (tinymce) {
|
||||
tinymce.destroy()
|
||||
tinymce.destroy();
|
||||
}
|
||||
},
|
||||
setContent(value) {
|
||||
window.tinymce.get(this.tinymceId).setContent(value)
|
||||
window.tinymce.get(this.tinymceId).setContent(value);
|
||||
},
|
||||
getContent() {
|
||||
window.tinymce.get(this.tinymceId).getContent()
|
||||
window.tinymce.get(this.tinymceId).getContent();
|
||||
},
|
||||
imageSuccessCBK(arr) {
|
||||
const _this = this
|
||||
const _this = this;
|
||||
arr.forEach(v => {
|
||||
window.tinymce.get(_this.tinymceId).insertContent(`<img class="wscnph" src="${v.url}" >`)
|
||||
})
|
||||
window.tinymce
|
||||
.get(_this.tinymceId)
|
||||
.insertContent(`<img class="wscnph" src="${v.url}" >`);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
@ -214,7 +221,7 @@ export default {
|
|||
position: relative;
|
||||
line-height: normal;
|
||||
}
|
||||
.tinymce-container>>>.mce-fullscreen {
|
||||
.tinymce-container >>> .mce-fullscreen {
|
||||
z-index: 10000;
|
||||
}
|
||||
.tinymce-textarea {
|
||||
|
|
|
@ -24,7 +24,7 @@ export default {
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
title: 'Vue Admin Template',
|
||||
title: '辐射学堂后台管理',
|
||||
logo: 'https://wpimg.wallstcn.com/69a1c46c-eb1c-4b46-8bd4-e9e686ef5251.png'
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ import Vue from 'vue'
|
|||
import 'normalize.css/normalize.css' // A modern alternative to CSS resets
|
||||
|
||||
import ElementUI from 'element-ui'
|
||||
import CKEditor from '@ckeditor/ckeditor5-vue';
|
||||
import 'element-ui/lib/theme-chalk/index.css'
|
||||
// import locale from 'element-ui/lib/locale/lang/en' // lang i18n
|
||||
|
||||
|
@ -32,7 +33,7 @@ if (process.env.NODE_ENV === 'production') {
|
|||
// Vue.use(ElementUI, { locale })
|
||||
// 如果想要中文版 element-ui,按如下方式声明
|
||||
Vue.use(ElementUI)
|
||||
|
||||
Vue.use(CKEditor)
|
||||
Vue.config.productionTip = false
|
||||
|
||||
new Vue({
|
||||
|
|
|
@ -64,25 +64,32 @@ export const constantRoutes = [
|
|||
*/
|
||||
export const asyncRoutes = [
|
||||
{
|
||||
path: '/news',
|
||||
path: '/cms',
|
||||
component: Layout,
|
||||
redirect: '/news/',
|
||||
name: 'News',
|
||||
redirect: '/cms/',
|
||||
name: 'CMS',
|
||||
meta: { title: '资讯文章', icon: 'peoples', perms: ['news_view'] },
|
||||
children: [
|
||||
{
|
||||
path: 'news',
|
||||
name: 'News',
|
||||
name: 'NewsList',
|
||||
component: () => import('@/views/news/news.vue'),
|
||||
meta: { title: '文章列表', icon: 'documentation', perms: ['news_view'] }
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
path: 'news/create',
|
||||
name: 'NewsCreate',
|
||||
component: () => import('@/views/news/newscreate.vue'),
|
||||
meta: { title: '新建文章', noCache: true, icon: '', perms: ['news_create']},
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'news/update',
|
||||
name: 'NewsUpdate',
|
||||
component: () => import('@/views/news/newsupdate.vue'),
|
||||
meta: { title: '编辑文章', noCache: true, icon: '', perms: ['news_update']},
|
||||
hidden: true
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
|
@ -12,5 +12,5 @@ module.exports = {
|
|||
* @type {boolean} true | false
|
||||
* @description Whether show the logo in sidebar
|
||||
*/
|
||||
sidebarLogo: false
|
||||
sidebarLogo: true
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<div style="margin-top:10px">
|
||||
<el-input
|
||||
v-model="listQuery.search"
|
||||
placeholder="名称"
|
||||
placeholder="搜索"
|
||||
style="width: 200px;"
|
||||
class="filter-item"
|
||||
@keyup.enter.native="handleSearch"
|
||||
|
@ -30,20 +30,14 @@
|
|||
max-height="600"
|
||||
>
|
||||
<el-table-column type="index" width="50"></el-table-column>
|
||||
<el-table-column align="left" label="名称">
|
||||
<template slot-scope="scope">{{ scope.row.name }}</template>
|
||||
<el-table-column align="left" label="标题">
|
||||
<template slot-scope="scope">{{ scope.row.title }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="left" label="工作类别">
|
||||
<template slot-scope="scope">{{ scope.row.workscope_name }}</template>
|
||||
<el-table-column align="left" label="新建时间">
|
||||
<template slot-scope="scope">{{ scope.row.create_time }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="left" label="总分">
|
||||
<template slot-scope="scope">{{ scope.row.total_score }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="left" label="通过分">
|
||||
<template slot-scope="scope">{{ scope.row.pass_score }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="left" label="限时(分钟)">
|
||||
<template slot-scope="scope">{{ scope.row.limit }}</template>
|
||||
<el-table-column align="left" label="更新时间">
|
||||
<template slot-scope="scope">{{ scope.row.update_time }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" label="操作">
|
||||
<template slot-scope="scope">
|
||||
|
@ -52,14 +46,14 @@
|
|||
size="small"
|
||||
@click="handleEdit(scope)"
|
||||
icon="el-icon-edit"
|
||||
:disabled="!checkPermission(['paper_update'])"
|
||||
:disabled="!checkPermission(['article_update'])"
|
||||
></el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
@click="handleDelete(scope)"
|
||||
icon="el-icon-delete"
|
||||
:disabled="!checkPermission(['paper_delete'])"
|
||||
:disabled="!checkPermission(['article_delete'])"
|
||||
></el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
@ -75,7 +69,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { getPaperList, deletePaper } from "@/api/examtest";
|
||||
import { getArticleList, deleteArticle } from "@/api/cms";
|
||||
import checkPermission from "@/utils/permission";
|
||||
import Pagination from "@/components/Pagination";
|
||||
|
||||
|
@ -104,7 +98,7 @@ export default {
|
|||
checkPermission,
|
||||
getList(query = this.listQuery) {
|
||||
this.listLoading = true;
|
||||
getPaperList(query).then(response => {
|
||||
getArticleList(query).then(response => {
|
||||
if(response.data.results){
|
||||
this.tableData = response.data;
|
||||
}
|
||||
|
@ -124,10 +118,10 @@ export default {
|
|||
this.getList();
|
||||
},
|
||||
handleAdd() {
|
||||
this.$router.push({path:"/news/create"})
|
||||
this.$router.push({path:"/cms/news/create"})
|
||||
},
|
||||
handleEdit(scope) {
|
||||
this.$router.push({path:"/sjmanage/paper/update",query:{id:scope.row.id}})
|
||||
this.$router.push({path:"/cms/news/update",query:{id:scope.row.id}})
|
||||
},
|
||||
handleDelete(scope) {
|
||||
this.$confirm('确认删除?', '提示', {
|
||||
|
@ -135,7 +129,7 @@ export default {
|
|||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
deletePaper(scope.row.id).then(response => {
|
||||
deleteArticle(scope.row.id).then(response => {
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '删除成功!'
|
||||
|
|
|
@ -1,36 +1,88 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<aside>
|
||||
Rich text is a core feature of the management backend, but at the same time it is a place with lots of pits. In the process of selecting rich texts, I also took a lot of detours. The common rich texts on the market have been basically used, and I finally chose Tinymce. See the more detailed rich text comparison and introduction.
|
||||
<a target="_blank" class="link-type" href="https://panjiachen.github.io/vue-element-admin-site/component/rich-editor.html">Documentation</a>
|
||||
</aside>
|
||||
<div>
|
||||
<tinymce v-model="content" :height="300" />
|
||||
<el-form
|
||||
:model="Form"
|
||||
:rules="rules"
|
||||
ref="Form"
|
||||
label-width="100px"
|
||||
status-icon
|
||||
>
|
||||
<el-form-item label="标题" prop="title">
|
||||
<el-input v-model="Form.title" style="width: 500"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="来源" prop="ifrom">
|
||||
<el-input v-model="Form.ifrom" style="width: 500"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="内容" prop="content">
|
||||
<tinymce v-model="Form.content" :height="400" :width="600"/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitForm('Form')" :loading="submitLoding">立即创建</el-button>
|
||||
<el-button type="warning" @click="goBack()">返回</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
</div>
|
||||
<div class="editor-content" v-html="content" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Tinymce from '@/components/Tinymce'
|
||||
import {createArticle} from "@/api/cms";
|
||||
|
||||
export default {
|
||||
name: 'TinymceDemo',
|
||||
components: { Tinymce },
|
||||
data() {
|
||||
return {
|
||||
content:
|
||||
`<h1 style="text-align: center;">Welcome to the TinyMCE demo!</h1><p style="text-align: center; font-size: 15px;"><img title="TinyMCE Logo" src="//www.tinymce.com/images/glyph-tinymce@2x.png" alt="TinyMCE Logo" width="110" height="97" /><ul>
|
||||
<li>Our <a href="//www.tinymce.com/docs/">documentation</a> is a great resource for learning how to configure TinyMCE.</li><li>Have a specific question? Visit the <a href="https://community.tinymce.com/forum/">Community Forum</a>.</li><li>We also offer enterprise grade support as part of <a href="https://tinymce.com/pricing">TinyMCE premium subscriptions</a>.</li>
|
||||
</ul>`
|
||||
Form:{
|
||||
title:'',
|
||||
ifrom:'',
|
||||
content:''
|
||||
},
|
||||
submitLoding: false,
|
||||
rules: {
|
||||
title: [
|
||||
{ required: true, message: "请输入", trigger: "blur" }
|
||||
],
|
||||
ifrom: [
|
||||
{ required: true, message: "请输入", trigger: "blur" }
|
||||
],
|
||||
content: [
|
||||
{ required: true, message: "请输入", trigger: "blur" }
|
||||
],
|
||||
},
|
||||
}
|
||||
},
|
||||
methods:{
|
||||
goBack() {
|
||||
this.$router.go(-1)
|
||||
},
|
||||
submitForm(formName) {
|
||||
this.$refs[formName].validate(valid => {
|
||||
if (valid) {
|
||||
// this.submitLoding = true
|
||||
createArticle(this.Form).then(response => {
|
||||
this.submitLoding = false
|
||||
if(response.code >= 200){
|
||||
this.$message({
|
||||
type: "success",
|
||||
message: "新建成功!"
|
||||
});
|
||||
this.goBack()
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.editor-content{
|
||||
margin-top: 20px;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<div>
|
||||
<el-form
|
||||
:model="Form"
|
||||
:rules="rules"
|
||||
ref="Form"
|
||||
label-width="100px"
|
||||
status-icon
|
||||
>
|
||||
<el-form-item label="标题" prop="title">
|
||||
<el-input v-model="Form.title" style="width: 500"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="来源" prop="ifrom">
|
||||
<el-input v-model="Form.ifrom" style="width: 500"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="内容" prop="content">
|
||||
<tinymce v-model="Form.content" :height="400" :width="600"/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitForm('Form')" :loading="submitLoding">保存</el-button>
|
||||
<el-button type="warning" @click="goBack()">返回</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Tinymce from '@/components/Tinymce'
|
||||
import {getArticle, updateArticle} from "@/api/cms";
|
||||
|
||||
export default {
|
||||
name: 'TinymceDemo',
|
||||
components: { Tinymce },
|
||||
data() {
|
||||
return {
|
||||
Form:{
|
||||
title:'',
|
||||
ifrom:'',
|
||||
content:''
|
||||
},
|
||||
submitLoding: false,
|
||||
rules: {
|
||||
title: [
|
||||
{ required: true, message: "请输入", trigger: "blur" }
|
||||
],
|
||||
ifrom: [
|
||||
{ required: true, message: "请输入", trigger: "blur" }
|
||||
],
|
||||
content: [
|
||||
{ required: true, message: "请输入", trigger: "blur" }
|
||||
],
|
||||
},
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.Form.id = this.$route.query.id //接收参数
|
||||
this.getArticle();
|
||||
},
|
||||
methods:{
|
||||
goBack() {
|
||||
this.$router.go(-1)
|
||||
},
|
||||
submitForm(formName) {
|
||||
this.$refs[formName].validate(valid => {
|
||||
if (valid) {
|
||||
// this.submitLoding = true
|
||||
updateArticle(this.Form.id, this.Form).then(response => {
|
||||
this.submitLoding = false
|
||||
if(response.code >= 200){
|
||||
this.$message({
|
||||
type: "success",
|
||||
message: "修改成功!"
|
||||
});
|
||||
this.goBack()
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
getArticle() {
|
||||
getArticle(this.Form.id).then(response => {
|
||||
this.Form = response.data ;
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
|
@ -0,0 +1,5 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class CmsConfig(AppConfig):
|
||||
name = 'cms'
|
|
@ -0,0 +1,31 @@
|
|||
# Generated by Django 3.0.4 on 2020-04-28 08:26
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.utils.timezone
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Article',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
|
||||
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
|
||||
('is_delete', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
|
||||
('title', models.CharField(max_length=60, verbose_name='标题')),
|
||||
('content', models.TextField(verbose_name='内容')),
|
||||
('ifrom', models.CharField(max_length=60, verbose_name='来源')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '文章',
|
||||
'verbose_name_plural': '文章',
|
||||
},
|
||||
),
|
||||
]
|
|
@ -0,0 +1,19 @@
|
|||
from django.db import models
|
||||
import django.utils.timezone as timezone
|
||||
from rbac.models import SoftCommonModel, CommonModel
|
||||
# Create your models here.
|
||||
|
||||
class Article(CommonModel):
|
||||
'''
|
||||
文章
|
||||
'''
|
||||
title = models.CharField(max_length=60, verbose_name='标题')
|
||||
content = models.TextField(verbose_name='内容')
|
||||
ifrom = models.CharField(max_length=60, verbose_name='来源')
|
||||
|
||||
class Meta:
|
||||
verbose_name = '文章'
|
||||
verbose_name_plural = verbose_name
|
||||
|
||||
def __str__(self):
|
||||
return self.title
|
|
@ -0,0 +1,13 @@
|
|||
from rest_framework import serializers
|
||||
from .models import Article
|
||||
|
||||
|
||||
class ArticelSerializer(serializers.ModelSerializer):
|
||||
"""
|
||||
文章序列化
|
||||
"""
|
||||
create_time = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S", required=False, read_only=True)
|
||||
update_time = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S", required=False, read_only=True)
|
||||
class Meta:
|
||||
model = Article
|
||||
fields = '__all__'
|
|
@ -0,0 +1,3 @@
|
|||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
|
@ -0,0 +1,11 @@
|
|||
from django.urls import path,include
|
||||
from .views import ArticleViewSet
|
||||
from rest_framework import routers
|
||||
|
||||
|
||||
router = routers.DefaultRouter()
|
||||
router.register('article', ArticleViewSet, basename="article")
|
||||
|
||||
urlpatterns = [
|
||||
path('', include(router.urls)),
|
||||
]
|
|
@ -0,0 +1,40 @@
|
|||
import json
|
||||
import random
|
||||
import warnings
|
||||
from calendar import timegm
|
||||
from datetime import datetime
|
||||
|
||||
import requests
|
||||
from django.db.models import Q
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from openpyxl import Workbook, load_workbook
|
||||
from rest_framework import status
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.filters import OrderingFilter, SearchFilter
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
|
||||
from rest_framework_jwt.serializers import (jwt_encode_handler,
|
||||
jwt_payload_handler)
|
||||
from rest_framework_jwt.settings import api_settings
|
||||
# Create your views here.
|
||||
|
||||
from .models import Article
|
||||
from .serializers import ArticelSerializer
|
||||
from utils.custom import CommonPagination
|
||||
class ArticleViewSet(ModelViewSet):
|
||||
"""
|
||||
文章:增删改查
|
||||
"""
|
||||
perms_map = [
|
||||
{'get': 'article_list'}, {'post': 'article_create'},
|
||||
{'put': 'article_update'}, {'delete': 'article_delete'}]
|
||||
queryset = Article.objects.filter(is_delete=0).all()
|
||||
serializer_class = ArticelSerializer
|
||||
pagination_class = CommonPagination
|
||||
filter_backends = [DjangoFilterBackend,SearchFilter, OrderingFilter]
|
||||
search_fields = ('^title','^content')
|
||||
ordering_fields = ('id',)
|
||||
ordering = ['-id']
|
|
@ -46,7 +46,8 @@ INSTALLED_APPS = [
|
|||
'crm',
|
||||
'question',
|
||||
'examtest',
|
||||
'analyse'
|
||||
'analyse',
|
||||
'cms'
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
|
|
|
@ -28,6 +28,7 @@ urlpatterns = [
|
|||
path('crm/', include('crm.urls')),
|
||||
path('question/', include('question.urls')),
|
||||
path('examtest/', include('examtest.urls')),
|
||||
path('cms/', include('cms.urls')),
|
||||
path('analyse/', include('analyse.urls')),
|
||||
path('token/', obtain_jwt_token),
|
||||
path('token/refresh/', refresh_jwt_token),
|
||||
|
|
Loading…
Reference in New Issue