Commit a1017fd1 authored by Zhang Xiaojie's avatar Zhang Xiaojie

发布及图片上传功能

parent 94f04a44
...@@ -5186,6 +5186,11 @@ ...@@ -5186,6 +5186,11 @@
"integrity": "sha1-P7rwIL/XlIhAcuomsel5HUWmKfA=", "integrity": "sha1-P7rwIL/XlIhAcuomsel5HUWmKfA=",
"dev": true "dev": true
}, },
"dropzone": {
"version": "5.9.2",
"resolved": "https://registry.npm.taobao.org/dropzone/download/dropzone-5.9.2.tgz",
"integrity": "sha1-CpDOP2sBHDkySE82j0vwYiNylFA="
},
"duplexer": { "duplexer": {
"version": "0.1.2", "version": "0.1.2",
"resolved": "https://registry.npm.taobao.org/duplexer/download/duplexer-0.1.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fduplexer%2Fdownload%2Fduplexer-0.1.2.tgz", "resolved": "https://registry.npm.taobao.org/duplexer/download/duplexer-0.1.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fduplexer%2Fdownload%2Fduplexer-0.1.2.tgz",
...@@ -13093,6 +13098,14 @@ ...@@ -13093,6 +13098,14 @@
"integrity": "sha1-HuO8mhbsv1EYvjNLsV+cRvgvWCU=", "integrity": "sha1-HuO8mhbsv1EYvjNLsV+cRvgvWCU=",
"dev": true "dev": true
}, },
"vue2-dropzone": {
"version": "3.6.0",
"resolved": "https://registry.npm.taobao.org/vue2-dropzone/download/vue2-dropzone-3.6.0.tgz",
"integrity": "sha1-tLtLZN4cu7O4jwSySHjgZ4ClFUY=",
"requires": {
"dropzone": "^5.5.1"
}
},
"vuex": { "vuex": {
"version": "3.6.2", "version": "3.6.2",
"resolved": "https://registry.nlark.com/vuex/download/vuex-3.6.2.tgz", "resolved": "https://registry.nlark.com/vuex/download/vuex-3.6.2.tgz",
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
"vue": "^2.6.11", "vue": "^2.6.11",
"vue-fragment": "^1.5.2", "vue-fragment": "^1.5.2",
"vue-router": "^3.2.0", "vue-router": "^3.2.0",
"vue2-dropzone": "^3.6.0",
"vuex": "^3.4.0" "vuex": "^3.4.0"
}, },
"devDependencies": { "devDependencies": {
......
<template>
<div>
<a-modal
title="上传图片"
:visible="visible"
:editor="editor"
:confirm-loading="confirmLoading"
@ok="handleOk"
@cancel="handleCancel"
okText="插入图片"
cancelText="取消"
>
<!-- Tab栏 -->
<button @click="tab = 1;"
:class="{ active: tab == 1 }"
class="tab text-gray-800 hover:text-color-primary rounded px-2 py-1 mb-5 mr-5">
通过链接上传
</button>
<button @click="tab = 2;"
:class="{ active: tab == 2 }"
class="tab text-gray-800 hover:text-color-primary rounded-sm px-2 py-1 mb-5">
拖动 / 选择文件上传图片
</button>
<!-- 上传区域 -->
<div v-if="tab == 1">
<a-input type="text" v-model="imageSrc" placeholder="请输入图片链接"/>
</div>
<div v-if="tab == 2">
<vue-dropzone
ref="myVueDropzone"
@vdropzone-success="vfileUploaded"
id="dropzone"
:options="dropzoneOptions"
>
</vue-dropzone>
</div>
</a-modal>
</div>
</template>
<script lang="ts">
import Vue from 'vue'
import vue2Dropzone from "vue2-dropzone"
import "vue2-dropzone/dist/vue2Dropzone.min.css"
export default Vue.extend({
components:{ vueDropzone: vue2Dropzone },
props: ["editor"],
data(){
return{
visible:false,
confirmLoading:false,
imageSrc:"",
dropzoneOptions: {
url: "/api/upload",
thumbnailWidth: 200,
maxFilesize: 0.5,
dictDefaultMessage: "拖动/选择文件上传图片",
},
tab:1,
}
},
// computed: {
// validImage() {
// return (
// this.imageSrc.match(/unsplash/) !== null ||this.imageSrc.match(/\.(jpeg|jpg|gif|png)$/) != null
// );
// },
// },
methods:{
showModal(){
this.visible = true
},
vfileUploaded(file:File|Blob) {
/** Here is where you get your URL/Base64 string or what ever.*/
},
handleOk(e:Event) {
if (this.imageSrc){
this.editor.chain().focus().setImage({ src:this.imageSrc }).run()
} else if( (this.$refs.myVueDropzone as any)){
(this.$refs.myVueDropzone as any).getAcceptedFiles().forEach( (file:any) => {
this.editor.chain().focus().setImage({ src: file.dataURL }).run()
})
}
this.handleCancel(e)
},
handleCancel(e:Event) {
this.visible = false
this.imageSrc = ""
this.tab = 1
},
}
})
</script>
<style scoped>
.tab.active{
background: #E6F7FF;
color:#1890ff;
border: none;
}
</style>
\ No newline at end of file
<template> <template>
<div v-if="editor" class="menubar" :editor="editor"> <div v-if="editor" class="menubar" :editor="editor">
<!-- 文件上传弹窗 -->
<ModalComponent ref="uploadModal" :editor="editor"/>
<!-- 菜单 -->
<button @click="addImage" <button @click="addImage"
class="menubar__button"> class="menubar__button">
<icon name="image" /> <icon name="image" />
...@@ -74,25 +77,26 @@ ...@@ -74,25 +77,26 @@
</div> </div>
</template> </template>
<script>
import Icon from "@/components/Icon/index.vue";
export default { <script lang="ts">
import Vue from 'vue'
import Icon from "@/components/Icon/index.vue"
import ModalComponent from "./ImageModal.vue"
export default Vue.extend({
props: ["editor"], props: ["editor"],
components: { components: {
Icon, Icon,
ModalComponent,
}, },
methods: { methods: {
addImage() { addImage() {
const url = window.prompt('请输入图片链接') (this.$refs.uploadModal as any).showModal()
if (url) {
this.editor.chain().focus().setImage({ src: url }).run()
}
}, },
}, },
}; })
</script> </script>
<style lang="scss"> <style scoped>
</style> </style>
\ No newline at end of file
...@@ -22,13 +22,16 @@ ...@@ -22,13 +22,16 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from 'vue'
import { message } from 'ant-design-vue'
function getBase64(img: Blob, callback: (any: any) => void) { function getBase64(img: Blob, callback: (any: any) => void) {
const reader = new FileReader(); const reader = new FileReader();
reader.addEventListener("load", () => callback(reader.result)); reader.addEventListener("load", () => callback(reader.result));
reader.readAsDataURL(img); reader.readAsDataURL(img);
} }
export default {
export default Vue.extend({
data(){ data(){
return{ return{
imageUrl: "", imageUrl: "",
...@@ -52,16 +55,16 @@ export default { ...@@ -52,16 +55,16 @@ export default {
beforeUpload(file:File) { beforeUpload(file:File) {
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png'; const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
if (!isJpgOrPng) { if (!isJpgOrPng) {
this.$message.error('You can only upload JPG file!'); message.error('You can only upload JPG file!');
} }
const isLt2M = file.size / 1024 / 1024 < 2; const isLt2M = file.size / 1024 / 1024 < 2;
if (!isLt2M) { if (!isLt2M) {
this.$message.error('Image must smaller than 2MB!'); message.error('Image must smaller than 2MB!');
} }
return isJpgOrPng && isLt2M; return isJpgOrPng && isLt2M;
}, },
} }
} })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
</template> </template>
<script> <script>
import { Editor, EditorContent,Image } from '@tiptap/vue-2' import { Editor, EditorContent } from '@tiptap/vue-2'
import StarterKit from '@tiptap/starter-kit' import StarterKit from '@tiptap/starter-kit'
import {Image as Timage} from '@tiptap/extension-image' import {Image as Timage} from '@tiptap/extension-image'
import EditorMenuBar from './editorMenuBar.vue' import EditorMenuBar from './editorMenuBar.vue'
...@@ -23,14 +23,20 @@ async function handleUpload(file) { ...@@ -23,14 +23,20 @@ async function handleUpload(file) {
export default { export default {
components: { components: {
EditorContent, EditorContent,
EditorMenuBar EditorMenuBar,
},
props:{
visible:{
type:Boolean,
default:true
}
}, },
data() { data() {
return { return {
editor: null, editor: null,
} }
}, },
mounted() { mounted() {
this.editor = new Editor({ this.editor = new Editor({
extensions: [ extensions: [
StarterKit, StarterKit,
...@@ -38,7 +44,9 @@ export default { ...@@ -38,7 +44,9 @@ export default {
], ],
autofocus: 'start', autofocus: 'start',
}) })
}, },
methods:{
},
beforeDestroy() { beforeDestroy() {
this.editor.destroy(); this.editor.destroy();
}, },
......
<template> <template>
<div class=" editor"> <div class=" editor">
<p class=" text-2xl font-bold mb-5">发布资讯</p> <p class=" text-2xl font-bold mb-5">发布活动</p>
<editor-title class=" mb-5"/> <editor-title class=" mb-5"/>
<!-- 上传概要图片 --> <!-- 上传概要图片 -->
<editor-upload/> <editor-upload/>
<!-- 编辑器 --> <!-- 编辑器 -->
<editor class="edit-news text-left"/> <editor class="edit-news text-left"/>
<!-- 发布操作 --> <!-- 发布操作 -->
<a-button type="primary" @click="onSubmit">确定发布</a-button> <a-button type="primary" @click="onSubmit" class=" mt-5">确定发布</a-button>
</div> </div>
</template> </template>
...@@ -20,7 +20,6 @@ import EditorUpload from '@/components/Editor/editorUpload.vue' ...@@ -20,7 +20,6 @@ import EditorUpload from '@/components/Editor/editorUpload.vue'
export default Vue.extend({ export default Vue.extend({
components:{ Editor,EditorTitle,EditorUpload }, components:{ Editor,EditorTitle,EditorUpload },
data(){ data(){
let editor: any = undefined
return{ return{
} }
}, },
......
<template> <template>
<div> <div class=" editor">
<p class=" text-2xl font-bold mb-5">发布资讯</p> <p class=" text-2xl font-bold mb-5">发布资讯</p>
<a-form-model :model="form" :label-col="labelCol" :wrapper-col="wrapperCol" ref="ruleForm" :rules="rules"> <div class=" flex content-between justify-between">
<a-form-model-item label="标题" prop="title"> <!-- 标题 -->
<a-input v-model="form.title" placeholder="请输入标题" style="width: 200px"/> <a-input v-model="title" placeholder="请输入标题" style="width: 40%"/>
</a-form-model-item> <!-- 作者 -->
<a-form-model-item label="作者名称" prop="author"> <a-input v-model="author" placeholder="请输入作者名称" style="width: 35%" />
<a-input v-model="form.author" placeholder="请输入作者名称" style="width: 200px"/> <!-- 文章分类 -->
</a-form-model-item> <a-select placeholder="资讯类别" style="width: 15%" v-model="type">
<a-form-model-item label="文章分类" prop="type"> <a-select-option v-for="(type,i) in articalType" :key="i">{{type}}</a-select-option>
<a-select :default-value="articalType[0]" style="width: 200px" v-model="form.type"> </a-select>
<a-select-option v-for="(type,i) in articalType" :key="i">{{type}}</a-select-option> </div>
</a-select> <!-- 上传概要图片 -->
</a-form-model-item> <editor-upload class=" mt-5"/>
<a-form-model-item label="上传概要图片" :required="true" prop="file" > <!-- 编辑器 -->
<a-upload <editor class="edit-news text-left"/>
name="file" <!-- 发布操作 -->
action="#" <a-button type="primary" @click="onSubmit" class=" mt-5">确定发布</a-button>
accept="image/*"
@change="handleChange"
required
>
<a-button style="width:200px"> <a-icon type="upload" /> 点击上传 </a-button>
</a-upload>
</a-form-model-item>
<!-- 编辑器 -->
<!-- 发布操作 -->
<a-form-model-item :wrapper-col="{ span: 11 }">
<a-button type="primary" @click="onSubmit">确定发布</a-button>
</a-form-model-item>
</a-form-model>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import { FormModel } from 'ant-design-vue'; import Editor from '@/components/Editor/index.vue'
import EditorTitle from '@/components/Editor/editorTitle.vue'
import EditorUpload from '@/components/Editor/editorUpload.vue'
export default Vue.extend({ export default Vue.extend({
components:{ Editor,EditorTitle,EditorUpload },
props:{ props:{
articalType:{ articalType:{
type:Array, type:Array,
...@@ -48,41 +38,14 @@ export default Vue.extend({ ...@@ -48,41 +38,14 @@ export default Vue.extend({
}, },
data(){ data(){
return{ return{
form:{ title:'',
title:'', author:'',
author:'', type:''
type:'',
},
labelCol: { span: 5 },
wrapperCol: { span:4},
rules:{
title: [{ required: true, message: '请输入标题', trigger: 'change' }],
type: [{ required: true, message: '请选择文章分类', trigger: 'change' }],
author: [{ required: true, message: '请输入作者名称', trigger: 'change' }],
file: [{ required: true, message: '请上传概要图片', trigger: 'change' }],
}
} }
}, },
methods:{ methods:{
handleChange(info:any) {
if (info.file.status !== 'uploading') {
console.log(info.file, info.fileList);
}
if (info.file.status === 'done') {
console.log(`${info.file.name} file uploaded successfully`);
} else if (info.file.status === 'error') {
console.log(`${info.file.name} file upload failed.`);
}
},
onSubmit() { onSubmit() {
(this.$refs.ruleForm as FormModel).validate(valid => {
if (valid) {
} else {
console.log('error submit!!');
return false;
}
});
}, },
} }
}) })
......
...@@ -8,7 +8,7 @@ module.exports = { ...@@ -8,7 +8,7 @@ module.exports = {
extend:{ extend:{
colors:{ colors:{
// 主题色 // 主题色
'color-primary':'#0099CC', 'color-primary':'#1890ff',
// 登录按钮 // 登录按钮
'btn-login':'#03CDFF' 'btn-login':'#03CDFF'
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment