feat: downgrade tinymce and fix editor config
This commit is contained in:
@ -115,7 +115,7 @@ export default defineNuxtConfig({
|
|||||||
},
|
},
|
||||||
|
|
||||||
build: {
|
build: {
|
||||||
transpile: ["vueuc", "@css-render/vue3-ssr","@unocss"],
|
transpile: ["vueuc", "@css-render/vue3-ssr","@unocss","@tinymce/tinymce-vue","tinymce"],
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
// 在这里引入插件
|
// 在这里引入插件
|
||||||
|
|||||||
@ -12,7 +12,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nuxtjs/axios": "^5.13.6",
|
"@nuxtjs/axios": "^5.13.6",
|
||||||
"@pinia/nuxt": "^0.11.2",
|
"@pinia/nuxt": "^0.11.2",
|
||||||
"@tinymce/tinymce-vue": "^6.3.0",
|
"@tinymce/tinymce-vue": "^5.0.0",
|
||||||
"@types/tinymce": "^5.5.0",
|
"@types/tinymce": "^5.5.0",
|
||||||
"decimal.js": "^10.6.0",
|
"decimal.js": "^10.6.0",
|
||||||
"echarts": "^6.0.0",
|
"echarts": "^6.0.0",
|
||||||
@ -20,7 +20,7 @@
|
|||||||
"nuxt": "^3.18.1",
|
"nuxt": "^3.18.1",
|
||||||
"pdfjs-dist": "^5.4.54",
|
"pdfjs-dist": "^5.4.54",
|
||||||
"pinia": "^3.0.3",
|
"pinia": "^3.0.3",
|
||||||
"tinymce": "^8.0.2",
|
"tinymce": "^6.2.0",
|
||||||
"vue": "^3.5.18",
|
"vue": "^3.5.18",
|
||||||
"vue-pdf-embed": "^2.1.3",
|
"vue-pdf-embed": "^2.1.3",
|
||||||
"vue-router": "^4.5.1",
|
"vue-router": "^4.5.1",
|
||||||
|
|||||||
@ -1,375 +1,380 @@
|
|||||||
<template>
|
<template>
|
||||||
<KlNavTab></KlNavTab>
|
<KlNavTab></KlNavTab>
|
||||||
<div class="mx-auto w-[1440px]">
|
<div class="mx-auto w-[1440px]">
|
||||||
<!-- 使用 el-form 重构表单区域 -->
|
<!-- 使用 el-form 重构表单区域 -->
|
||||||
<el-form ref="formRef" inline :model="formData" label-width="110px" class="custom-form mb-[20px] mt-[20px] border rounded p-[20px]!">
|
<el-form ref="formRef" inline :model="formData" label-width="110px" class="custom-form mb-[20px] mt-[20px] border rounded p-[20px]!">
|
||||||
<el-form-item label="标题:" prop="postsTitle" :rules="{ required: true, message: '请输入标题', trigger: 'blur' }">
|
<el-form-item label="标题:" prop="postsTitle" :rules="{ required: true, message: '请输入标题', trigger: 'blur' }">
|
||||||
<el-input v-model="formData.postsTitle" placeholder="请输入标题" class="w-[300px]!" minlength="4" maxlength="40"></el-input>
|
<el-input v-model="formData.postsTitle" placeholder="请输入标题" class="w-[300px]!" minlength="4" maxlength="40"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="分类:" class="mb-[10px]" prop="projectDicId" :rules="{ required: true, message: '请选择分类', trigger: ['blur', 'change'] }">
|
<el-form-item label="分类:" class="mb-[10px]" prop="projectDicId" :rules="{ required: true, message: '请选择分类', trigger: ['blur', 'change'] }">
|
||||||
<el-select v-model="formData.projectDicId" placeholder="请选择分类" class="w-[300px]!">
|
<el-select v-model="formData.projectDicId" placeholder="请选择分类" class="w-[300px]!">
|
||||||
<el-option v-for="item in projectTypeList" :key="item.id" :label="item.name" :value="item.id" />
|
<el-option v-for="item in projectTypeList" :key="item.id" :label="item.name" :value="item.id" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="标签:" class="mb-[10px]" prop="postsTags" :rules="{ required: true, message: '请输入标签', trigger: ['blur', 'change'] }">
|
|
||||||
<el-select
|
|
||||||
v-model="formData.postsTags"
|
|
||||||
:remote-method="remoteMethod"
|
|
||||||
:loading="loading"
|
|
||||||
filterable
|
|
||||||
remote
|
|
||||||
multiple
|
|
||||||
placeholder="请输入搜索标签"
|
|
||||||
class="w-[300px]!"
|
|
||||||
>
|
|
||||||
<el-option v-for="(item, index) in labelsList" :key="index" :label="item" :value="item" />
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="频道列表:" class="mb-[10px]" prop="channelId" :rules="{ required: true, message: '请选择频道', trigger: ['blur', 'change'] }">
|
|
||||||
<el-select v-model="formData.channelId" placeholder="请选择频道" class="w-[300px]!">
|
|
||||||
<el-option v-for="item in channelIdList" :key="item.channelId" :label="item.channelTitle" :value="item.channelId" />
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
<!-- <el-form-item label="上传封面:" prop="postsCover" :rules="{ required: true, message: '请上传封面', trigger: ['blur', 'change'] }">
|
|
||||||
<KlUploader v-model:file-list="formData.postsCover" :limit="1" :size="1" tips="上传图片支持jpg/gif/png格式"> </KlUploader>
|
|
||||||
</el-form-item> -->
|
|
||||||
</el-form>
|
|
||||||
|
|
||||||
<Editor :id="tinymceId" v-model="myValue" :init="init" :disabled="disabled" :placeholder="placeholder" />
|
|
||||||
<!-- 按钮区域 -->
|
|
||||||
<div class="mt-[20px] flex justify-end">
|
|
||||||
<el-button :loading="post_loading" class="mr-[10px]" @click="previewContent">预览</el-button>
|
|
||||||
<el-button :loading="post_loading" type="primary" @click="saveContent">发表</el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { keywords } from '~/api/upnew/index'
|
|
||||||
import { reactive, ref, onMounted } from 'vue'
|
|
||||||
import { useRouter, useRoute } from 'vue-router'
|
|
||||||
const router = useRouter()
|
|
||||||
const route = useRoute()
|
|
||||||
import { create, list } from '~/api/channel/index'
|
|
||||||
import { parent,parentV2 } from '~/api/upnew/index'
|
|
||||||
import { upload } from '~/api/common/index' // 自定义上传方法
|
|
||||||
import Editor from '@tinymce/tinymce-vue'
|
|
||||||
import tinymce from 'tinymce/tinymce'
|
|
||||||
import 'tinymce/themes/silver'
|
|
||||||
import 'tinymce/themes/silver/theme'
|
|
||||||
import 'tinymce/models/dom'
|
|
||||||
import 'tinymce/icons/default'
|
|
||||||
import 'tinymce/icons/default/icons'
|
|
||||||
// 引入编辑器插件
|
|
||||||
import 'tinymce/plugins/code' //编辑源码
|
|
||||||
import 'tinymce/plugins/image' //插入编辑图片
|
|
||||||
import 'tinymce/plugins/media' //插入视频
|
|
||||||
import 'tinymce/plugins/link' //超链接
|
|
||||||
import 'tinymce/plugins/preview' //预览
|
|
||||||
// import 'tinymce/plugins/template' //模板
|
|
||||||
import 'tinymce/plugins/table' //表格
|
|
||||||
import 'tinymce/plugins/pagebreak' //分页
|
|
||||||
import 'tinymce/plugins/lists' //列
|
|
||||||
import 'tinymce/plugins/advlist' //列
|
|
||||||
import 'tinymce/plugins/quickbars' //快速工具条
|
|
||||||
import 'tinymce/plugins/wordcount' // 字数统计插件
|
|
||||||
// import '~/assets/tinymce/langs/zh-Hans.js' //下载后的语言包
|
|
||||||
// import 'tinymce/skins/content/default/content.css'
|
|
||||||
// 获取从其他地方传过来的参数
|
|
||||||
const channelId = route.query.channelId as string
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
value: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
placeholder: {
|
|
||||||
type: String,
|
|
||||||
default: '请输入帖子内容',
|
|
||||||
},
|
|
||||||
height: {
|
|
||||||
type: Number,
|
|
||||||
default: 500,
|
|
||||||
},
|
|
||||||
disabled: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
plugins: {
|
|
||||||
type: [String, Array],
|
|
||||||
default: 'code image link preview table quickbars pagebreak lists advlist',
|
|
||||||
},
|
|
||||||
toolbar: {
|
|
||||||
type: [String, Array],
|
|
||||||
default:
|
|
||||||
'undo redo codesample bold italic underline strikethrough link alignleft aligncenter alignright alignjustify \
|
|
||||||
bullist numlist outdent indent removeformat forecolor backcolor |formatselect fontselect fontsizeselect | \
|
|
||||||
blocks fontfamily fontsize pagebreak lists image customvideoupload table preview | code selectall',
|
|
||||||
},
|
|
||||||
templates: {
|
|
||||||
type: Array,
|
|
||||||
default: () => [],
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
type: Object,
|
|
||||||
default: () => ({}),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
//用于接收外部传递进来的富文本
|
|
||||||
const myValue = ref(props.value)
|
|
||||||
const tinymceId = ref('vue-tinymce-' + +new Date() + ((Math.random() * 1000).toFixed(0) + ''))
|
|
||||||
const init = reactive({
|
|
||||||
selector: '#' + tinymceId.value, //富文本编辑器的id,
|
|
||||||
language_url: '~/staic/tinymce/langs/zh_CN.js', // 语言包的路径,具体路径看自己的项目,文档后面附上中文js文件
|
|
||||||
language: 'zh-Hans', //语言
|
|
||||||
skin_url: '~/staic/tinymce/skins/ui/oxide', // skin路径,具体路径看自己的项目
|
|
||||||
content_css: '~/staic/tinymce/skins/content/default/content.css',
|
|
||||||
menubar: true, //顶部菜单栏显示
|
|
||||||
statusbar: true, // 底部的状态栏
|
|
||||||
plugins: props.plugins,
|
|
||||||
toolbar: props.toolbar,
|
|
||||||
toolbar_mode: 'sliding',
|
|
||||||
font_formats: 'Arial=arial,helvetica,sans-serif; 宋体=SimSun; 微软雅黑=Microsoft Yahei; Impact=impact,chicago;', //字体
|
|
||||||
paste_convert_word_fake_lists: false, // 插入word文档需要该属性
|
|
||||||
font_size_formats: '12px 14px 16px 18px 22px 24px 36px 72px', //文字大小
|
|
||||||
height: props.height, //编辑器高度
|
|
||||||
placeholder: props.placeholder,
|
|
||||||
branding: false, //是否禁用"Powered by TinyMCE"
|
|
||||||
promotion: false, //禁用升级按钮
|
|
||||||
image_dimensions: false, //去除宽高属性
|
|
||||||
paste_webkit_styles: 'all',
|
|
||||||
paste_merge_formats: true,
|
|
||||||
nonbreaking_force_tab: false,
|
|
||||||
paste_auto_cleanup_on_paste: false,
|
|
||||||
file_picker_types: 'file',
|
|
||||||
resize: true,
|
|
||||||
elementpath: true,
|
|
||||||
content_style: `img {max-width:100%;} body{background-color: #fff;}`, // 直接自定义可编辑区域的css样式
|
|
||||||
templates: props.templates,
|
|
||||||
quickbars_selection_toolbar: 'forecolor backcolor bold italic underline strikethrough link',
|
|
||||||
quickbars_image_toolbar: 'alignleft aligncenter alignright',
|
|
||||||
quickbars_insert_toolbar: false,
|
|
||||||
image_caption: true,
|
|
||||||
image_advtab: true,
|
|
||||||
convert_urls: false,
|
|
||||||
images_upload_url: import.meta.env.VITE_BASE_API,
|
|
||||||
images_upload_handler: function (blobInfo: any, progress: any) {
|
|
||||||
console.log(blobInfo, progress)
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const data = new FormData()
|
|
||||||
data.append('file', blobInfo.blob())
|
|
||||||
data.append('fieldName', blobInfo.filename())
|
|
||||||
upload('/prod-api/app-api/infra/file/upload', data)
|
|
||||||
.then((res) => {
|
|
||||||
resolve(res.data)
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
reject('Image upload failed')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
// 添加自定义按钮
|
|
||||||
setup: function (editor: any) {
|
|
||||||
if (process.client) {
|
|
||||||
// 注册一个新的视频上传按钮
|
|
||||||
editor.ui.registry.addButton('customvideoupload', {
|
|
||||||
icon: 'embed', // 使用嵌入媒体图标
|
|
||||||
tooltip: '上传视频',
|
|
||||||
onAction: function () {
|
|
||||||
// 创建文件输入元素
|
|
||||||
const input = document.createElement('input')
|
|
||||||
input.setAttribute('type', 'file')
|
|
||||||
input.setAttribute('accept', 'video/*')
|
|
||||||
|
|
||||||
// 处理文件选择事件
|
|
||||||
input.onchange = function () {
|
|
||||||
if (input.files && input.files[0]) {
|
|
||||||
const file = input.files[0]
|
|
||||||
const data = new FormData()
|
|
||||||
data.append('file', file)
|
|
||||||
data.append('fieldName', file.name)
|
|
||||||
|
|
||||||
// 可以在这里添加上传进度显示
|
|
||||||
|
|
||||||
upload('/prod-api/app-api/infra/file/upload', data)
|
|
||||||
.then((res) => {
|
|
||||||
// 插入视频到编辑器
|
|
||||||
editor.insertContent(`
|
|
||||||
<video controls width="400">
|
|
||||||
<source src="${res.data}" type="video/${file.name.split('.').pop()}">
|
|
||||||
您的浏览器不支持视频标签
|
|
||||||
</video>
|
|
||||||
`)
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error('视频上传失败:', error)
|
|
||||||
// 可以添加错误提示
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 触发文件选择
|
|
||||||
input.click()
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
<el-form-item label="标签:" class="mb-[10px]" prop="postsTags" :rules="{ required: true, message: '请输入标签', trigger: ['blur', 'change'] }">
|
||||||
},
|
<el-select
|
||||||
|
v-model="formData.postsTags"
|
||||||
preview_styles: true,
|
:remote-method="remoteMethod"
|
||||||
...props.options,
|
:loading="loading"
|
||||||
})
|
filterable
|
||||||
|
remote
|
||||||
// 表单数据
|
multiple
|
||||||
const formData = ref({
|
placeholder="请输入搜索标签"
|
||||||
projectDicId: undefined,
|
class="w-[300px]!"
|
||||||
postsTags: [],
|
>
|
||||||
postsCover: [] as any,
|
<el-option v-for="(item, index) in labelsList" :key="index" :label="item" :value="item" />
|
||||||
postsTitle: '',
|
</el-select>
|
||||||
channelId: channelId || undefined,
|
</el-form-item>
|
||||||
})
|
<el-form-item label="频道列表:" class="mb-[10px]" prop="channelId" :rules="{ required: true, message: '请选择频道', trigger: ['blur', 'change'] }">
|
||||||
|
<el-select v-model="formData.channelId" placeholder="请选择频道" class="w-[300px]!">
|
||||||
const formRef = ref()
|
<el-option v-for="item in channelIdList" :key="item.channelId" :label="item.channelTitle" :value="item.channelId" />
|
||||||
const post_loading = ref(false)
|
</el-select>
|
||||||
const saveContent = () => {
|
</el-form-item>
|
||||||
formRef.value.validate().then(() => {
|
<!-- <el-form-item label="上传封面:" prop="postsCover" :rules="{ required: true, message: '请上传封面', trigger: ['blur', 'change'] }">
|
||||||
if (!myValue.value) {
|
<KlUploader v-model:file-list="formData.postsCover" :limit="1" :size="1" tips="上传图片支持jpg/gif/png格式"> </KlUploader>
|
||||||
ElMessage.error('请输入帖子内容')
|
</el-form-item> -->
|
||||||
return
|
</el-form>
|
||||||
}
|
|
||||||
post_loading.value = true
|
<ClientOnly>
|
||||||
create({
|
<Editor :id="tinymceId" v-model="myValue" :init="init" :disabled="disabled" :placeholder="placeholder" />
|
||||||
postsTitle: formData.value.postsTitle,
|
</ClientOnly>
|
||||||
// postsCover: formData.value.postsCover[0].url,
|
<!-- 按钮区域 -->
|
||||||
postsTags: formData.value.postsTags.join(','),
|
<div class="mt-[20px] flex justify-end">
|
||||||
postsContent: myValue.value,
|
<el-button :loading="post_loading" class="mr-[10px]" @click="previewContent">预览</el-button>
|
||||||
projectDicId: formData.value.projectDicId,
|
<el-button :loading="post_loading" type="primary" @click="saveContent">发表</el-button>
|
||||||
channelId: formData.value.channelId,
|
</div>
|
||||||
})
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { keywords } from '~/api/upnew/index'
|
||||||
|
import { reactive, ref, onMounted } from 'vue'
|
||||||
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
|
import { create, list } from '~/api/channel/index'
|
||||||
|
import { parent,parentV2 } from '~/api/upnew/index'
|
||||||
|
import { upload } from '~/api/common/index' // 自定义上传方法
|
||||||
|
import Editor from '@tinymce/tinymce-vue'
|
||||||
|
import tinymce from 'tinymce/tinymce'
|
||||||
|
import 'tinymce/themes/silver'
|
||||||
|
import 'tinymce/themes/silver/theme'
|
||||||
|
import 'tinymce/models/dom'
|
||||||
|
import 'tinymce/icons/default'
|
||||||
|
import 'tinymce/icons/default/icons'
|
||||||
|
// 引入编辑器插件
|
||||||
|
import 'tinymce/plugins/code' //编辑源码
|
||||||
|
import 'tinymce/plugins/image' //插入编辑图片
|
||||||
|
import 'tinymce/plugins/media' //插入视频
|
||||||
|
import 'tinymce/plugins/link' //超链接
|
||||||
|
import 'tinymce/plugins/preview' //预览
|
||||||
|
// import 'tinymce/plugins/template' //模板
|
||||||
|
import 'tinymce/plugins/table' //表格
|
||||||
|
import 'tinymce/plugins/pagebreak' //分页
|
||||||
|
import 'tinymce/plugins/lists' //列
|
||||||
|
import 'tinymce/plugins/advlist' //列
|
||||||
|
import 'tinymce/plugins/quickbars' //快速工具条
|
||||||
|
import 'tinymce/plugins/wordcount' // 字数统计插件
|
||||||
|
// import 'tinymce/langs/zh-Hans'
|
||||||
|
// import 'tinymce/skins/ui/oxide/skin.min.css'
|
||||||
|
// import 'tinymce/skins/ui/oxide/content.min.css'
|
||||||
|
// import 'tinymce/skins/content/default/content.css'
|
||||||
|
// import '~/assets/tinymce/langs/zh-Hans.js' //下载后的语言包
|
||||||
|
// import 'tinymce/skins/content/default/content.css'
|
||||||
|
// 获取从其他地方传过来的参数
|
||||||
|
const channelId = route.query.channelId as string
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: '请输入帖子内容',
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
type: Number,
|
||||||
|
default: 500,
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
type: [String, Array],
|
||||||
|
default: 'code image link preview table quickbars pagebreak lists advlist',
|
||||||
|
},
|
||||||
|
toolbar: {
|
||||||
|
type: [String, Array],
|
||||||
|
default:
|
||||||
|
'undo redo codesample bold italic underline strikethrough link alignleft aligncenter alignright alignjustify \
|
||||||
|
bullist numlist outdent indent removeformat forecolor backcolor |formatselect fontselect fontsizeselect | \
|
||||||
|
blocks fontfamily fontsize pagebreak lists image customvideoupload table preview | code selectall',
|
||||||
|
},
|
||||||
|
templates: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
//用于接收外部传递进来的富文本
|
||||||
|
const myValue = ref(props.value)
|
||||||
|
const tinymceId = ref('vue-tinymce-' + +new Date() + ((Math.random() * 1000).toFixed(0) + ''))
|
||||||
|
const init = reactive({
|
||||||
|
selector: '#' + tinymceId.value, //富文本编辑器的id,
|
||||||
|
language_url: '/_nuxt/static/tinymce/langs/zh_CN.js', // 语言包的路径,具体路径看自己的项目,文档后面附上中文js文件
|
||||||
|
language: 'zh-Hans', //语言
|
||||||
|
skin_url: '/_nuxt/static/tinymce/skins/ui/oxide', // skin路径,具体路径看自己的项目
|
||||||
|
content_css: '/_nuxt/static/tinymce/skins/content/default/content.css',
|
||||||
|
menubar: true, //顶部菜单栏显示
|
||||||
|
statusbar: true, // 底部的状态栏
|
||||||
|
plugins: props.plugins,
|
||||||
|
toolbar: props.toolbar,
|
||||||
|
toolbar_mode: 'sliding',
|
||||||
|
font_formats: 'Arial=arial,helvetica,sans-serif; 宋体=SimSun; 微软雅黑=Microsoft Yahei; Impact=impact,chicago;', //字体
|
||||||
|
paste_convert_word_fake_lists: false, // 插入word文档需要该属性
|
||||||
|
font_size_formats: '12px 14px 16px 18px 22px 24px 36px 72px', //文字大小
|
||||||
|
height: props.height, //编辑器高度
|
||||||
|
placeholder: props.placeholder,
|
||||||
|
branding: false, //是否禁用"Powered by TinyMCE"
|
||||||
|
promotion: false, //禁用升级按钮
|
||||||
|
image_dimensions: false, //去除宽高属性
|
||||||
|
paste_webkit_styles: 'all',
|
||||||
|
paste_merge_formats: true,
|
||||||
|
nonbreaking_force_tab: false,
|
||||||
|
paste_auto_cleanup_on_paste: false,
|
||||||
|
file_picker_types: 'file',
|
||||||
|
resize: true,
|
||||||
|
elementpath: true,
|
||||||
|
content_style: `img {max-width:100%;} body{background-color: #fff;}`, // 直接自定义可编辑区域的css样式
|
||||||
|
templates: props.templates,
|
||||||
|
quickbars_selection_toolbar: 'forecolor backcolor bold italic underline strikethrough link',
|
||||||
|
quickbars_image_toolbar: 'alignleft aligncenter alignright',
|
||||||
|
quickbars_insert_toolbar: false,
|
||||||
|
image_caption: true,
|
||||||
|
image_advtab: true,
|
||||||
|
convert_urls: false,
|
||||||
|
images_upload_url: import.meta.env.VITE_BASE_API,
|
||||||
|
images_upload_handler: function (blobInfo: any, progress: any) {
|
||||||
|
console.log(blobInfo, progress)
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const data = new FormData()
|
||||||
|
data.append('file', blobInfo.blob())
|
||||||
|
data.append('fieldName', blobInfo.filename())
|
||||||
|
upload('/prod-api/app-api/infra/file/upload', data)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
console.log(res)
|
resolve(res.data)
|
||||||
if (res.code === 0) {
|
|
||||||
ElMessage.success('发表成功')
|
|
||||||
router.push('/communication/channel')
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch(() => {
|
||||||
console.log(err)
|
reject('Image upload failed')
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
post_loading.value = false
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
},
|
||||||
const previewContent = () => {
|
|
||||||
// 获取编辑器实例
|
// 添加自定义按钮
|
||||||
const editor = tinymce.get(tinymceId.value)
|
setup: function (editor: any) {
|
||||||
// 调用编辑器的预览命令
|
if (process.client) {
|
||||||
if (editor) {
|
// 注册一个新的视频上传按钮
|
||||||
editor.execCommand('mcePreview')
|
editor.ui.registry.addButton('customvideoupload', {
|
||||||
|
icon: 'embed', // 使用嵌入媒体图标
|
||||||
|
tooltip: '上传视频',
|
||||||
|
onAction: function () {
|
||||||
|
// 创建文件输入元素
|
||||||
|
const input = document.createElement('input')
|
||||||
|
input.setAttribute('type', 'file')
|
||||||
|
input.setAttribute('accept', 'video/*')
|
||||||
|
|
||||||
|
// 处理文件选择事件
|
||||||
|
input.onchange = function () {
|
||||||
|
if (input.files && input.files[0]) {
|
||||||
|
const file = input.files[0]
|
||||||
|
const data = new FormData()
|
||||||
|
data.append('file', file)
|
||||||
|
data.append('fieldName', file.name)
|
||||||
|
|
||||||
|
// 可以在这里添加上传进度显示
|
||||||
|
|
||||||
|
upload('/prod-api/app-api/infra/file/upload', data)
|
||||||
|
.then((res) => {
|
||||||
|
// 插入视频到编辑器
|
||||||
|
editor.insertContent(`
|
||||||
|
<video controls width="400">
|
||||||
|
<source src="${res.data}" type="video/${file.name.split('.').pop()}">
|
||||||
|
您的浏览器不支持视频标签
|
||||||
|
</video>
|
||||||
|
`)
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('视频上传失败:', error)
|
||||||
|
// 可以添加错误提示
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 触发文件选择
|
||||||
|
input.click()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
//在onMounted中初始化编辑器
|
|
||||||
onMounted(() => {
|
preview_styles: true,
|
||||||
if (process.client) {
|
...props.options,
|
||||||
getParent()
|
})
|
||||||
getChannelIdList()
|
|
||||||
tinymce.init({})
|
// 表单数据
|
||||||
}
|
const formData = ref({
|
||||||
})
|
projectDicId: undefined,
|
||||||
|
postsTags: [],
|
||||||
/** 获取频道列表 */
|
postsCover: [] as any,
|
||||||
const channelIdList = ref<any>([])
|
postsTitle: '',
|
||||||
const getChannelIdList = () => {
|
channelId: channelId || undefined,
|
||||||
list().then((res) => {
|
})
|
||||||
channelIdList.value = res.data
|
|
||||||
|
const formRef = ref()
|
||||||
|
const post_loading = ref(false)
|
||||||
|
const saveContent = () => {
|
||||||
|
formRef.value.validate().then(() => {
|
||||||
|
if (!myValue.value) {
|
||||||
|
ElMessage.error('请输入帖子内容')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
post_loading.value = true
|
||||||
|
create({
|
||||||
|
postsTitle: formData.value.postsTitle,
|
||||||
|
// postsCover: formData.value.postsCover[0].url,
|
||||||
|
postsTags: formData.value.postsTags.join(','),
|
||||||
|
postsContent: myValue.value,
|
||||||
|
projectDicId: formData.value.projectDicId,
|
||||||
|
channelId: formData.value.channelId,
|
||||||
})
|
})
|
||||||
|
.then((res) => {
|
||||||
|
console.log(res)
|
||||||
|
if (res.code === 0) {
|
||||||
|
ElMessage.success('发表成功')
|
||||||
|
router.push('/communication/channel')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
post_loading.value = false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const previewContent = () => {
|
||||||
|
// 获取编辑器实例
|
||||||
|
const editor = tinymce.get(tinymceId.value)
|
||||||
|
// 调用编辑器的预览命令
|
||||||
|
if (editor) {
|
||||||
|
editor.execCommand('mcePreview')
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
//在onMounted中初始化编辑器
|
||||||
const projectTypeList = ref<any>([])
|
onMounted(async () => {
|
||||||
/** 获取分类下拉框 */
|
if (process.client) {
|
||||||
const getParent = () => {
|
getParent()
|
||||||
parentV2({
|
getChannelIdList()
|
||||||
|
tinymce.init({})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
/** 获取频道列表 */
|
||||||
|
const channelIdList = ref<any>([])
|
||||||
|
const getChannelIdList = () => {
|
||||||
|
list().then((res) => {
|
||||||
|
channelIdList.value = res.data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const projectTypeList = ref<any>([])
|
||||||
|
/** 获取分类下拉框 */
|
||||||
|
const getParent = () => {
|
||||||
|
parentV2({
|
||||||
|
type: 1,
|
||||||
|
parentId: 0,
|
||||||
|
}).then((res) => {
|
||||||
|
projectTypeList.value = res.data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const loading = ref(false)
|
||||||
|
/** 获取标签 */
|
||||||
|
const labelsList = ref<any>([])
|
||||||
|
const remoteMethod = (query: string) => {
|
||||||
|
if (query) {
|
||||||
|
loading.value = true
|
||||||
|
keywords({
|
||||||
type: 1,
|
type: 1,
|
||||||
parentId: 0,
|
keywords: query,
|
||||||
}).then((res) => {
|
|
||||||
projectTypeList.value = res.data
|
|
||||||
})
|
})
|
||||||
}
|
.then((res) => {
|
||||||
|
labelsList.value = res.data
|
||||||
|
|
||||||
const loading = ref(false)
|
|
||||||
/** 获取标签 */
|
|
||||||
const labelsList = ref<any>([])
|
|
||||||
const remoteMethod = (query: string) => {
|
|
||||||
if (query) {
|
|
||||||
loading.value = true
|
|
||||||
keywords({
|
|
||||||
type: 1,
|
|
||||||
keywords: query,
|
|
||||||
})
|
})
|
||||||
.then((res) => {
|
.finally(() => {
|
||||||
labelsList.value = res.data
|
loading.value = false
|
||||||
})
|
})
|
||||||
.finally(() => {
|
} else {
|
||||||
loading.value = false
|
labelsList.value = []
|
||||||
})
|
|
||||||
} else {
|
|
||||||
labelsList.value = []
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</script>
|
}
|
||||||
|
</script>
|
||||||
<style scoped>
|
|
||||||
.custom-form {
|
<style scoped>
|
||||||
border: 2px solid #eeeeee;
|
.custom-form {
|
||||||
border-radius: 4px;
|
border: 2px solid #eeeeee;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cover-uploader {
|
||||||
|
:deep(.el-upload) {
|
||||||
|
width: fit-content;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
.upload-container {
|
|
||||||
display: flex;
|
.image-error {
|
||||||
flex-direction: column;
|
display: flex;
|
||||||
}
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
.cover-uploader {
|
justify-content: center;
|
||||||
:deep(.el-upload) {
|
color: #909399;
|
||||||
width: fit-content;
|
height: 100%;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
.image-actions {
|
||||||
.image-error {
|
display: flex;
|
||||||
display: flex;
|
justify-content: center;
|
||||||
flex-direction: column;
|
}
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
:deep(.el-form-item__label) {
|
||||||
color: #909399;
|
font-weight: normal;
|
||||||
height: 100%;
|
}
|
||||||
}
|
|
||||||
|
:deep(.el-button--primary.is-link) {
|
||||||
.image-actions {
|
padding: 0;
|
||||||
display: flex;
|
height: auto;
|
||||||
justify-content: center;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-form-item__label) {
|
.text-gray-500 {
|
||||||
font-weight: normal;
|
color: #999;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-button--primary.is-link) {
|
.text-12px {
|
||||||
padding: 0;
|
font-size: 12px;
|
||||||
height: auto;
|
}
|
||||||
font-size: 14px;
|
</style>
|
||||||
}
|
|
||||||
|
|
||||||
.text-gray-500 {
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-12px {
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
0
plugins/tinymce.ts
Normal file
0
plugins/tinymce.ts
Normal file
18
yarn.lock
18
yarn.lock
@ -1730,10 +1730,12 @@
|
|||||||
resolved "https://registry.npmmirror.com/@speed-highlight/core/-/core-1.2.7.tgz"
|
resolved "https://registry.npmmirror.com/@speed-highlight/core/-/core-1.2.7.tgz"
|
||||||
integrity sha512-0dxmVj4gxg3Jg879kvFS/msl4s9F3T9UXC1InxgOf7t5NvcPD97u/WTA5vL/IxWHMn7qSxBozqrnnE2wvl1m8g==
|
integrity sha512-0dxmVj4gxg3Jg879kvFS/msl4s9F3T9UXC1InxgOf7t5NvcPD97u/WTA5vL/IxWHMn7qSxBozqrnnE2wvl1m8g==
|
||||||
|
|
||||||
"@tinymce/tinymce-vue@^6.3.0":
|
"@tinymce/tinymce-vue@^5.0.0":
|
||||||
version "6.3.0"
|
version "5.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/@tinymce/tinymce-vue/-/tinymce-vue-6.3.0.tgz#1ea4d57eea71e48aa71da9d8de98472f8505b2d4"
|
resolved "https://registry.yarnpkg.com/@tinymce/tinymce-vue/-/tinymce-vue-5.1.1.tgz#0879787e07833a4316b2eaf0417c7c6a2abce86b"
|
||||||
integrity sha512-DSP8Jhd3XqCCliTnusfbmz3D8GqQ4iRzkc4aadYHDcJPVjkaqopJ61McOdH82CSy599vGLkPjGzqJYWJkRMiUA==
|
integrity sha512-iO57HOWesFOhsaqjA5Ea6sDvQBmJJH3/dq00Uvg7metlct2kLF+ctRgoDsetLt6gmeZ7COPftr814/XzqnJ/dg==
|
||||||
|
dependencies:
|
||||||
|
tinymce "^6.0.0 || ^5.5.1"
|
||||||
|
|
||||||
"@tybys/wasm-util@^0.10.0":
|
"@tybys/wasm-util@^0.10.0":
|
||||||
version "0.10.0"
|
version "0.10.0"
|
||||||
@ -6479,10 +6481,10 @@ tinymce@*:
|
|||||||
resolved "https://registry.npmmirror.com/tinymce/-/tinymce-8.0.2.tgz#babaaa40c154d0832b41332f25f3485b5887a6f2"
|
resolved "https://registry.npmmirror.com/tinymce/-/tinymce-8.0.2.tgz#babaaa40c154d0832b41332f25f3485b5887a6f2"
|
||||||
integrity sha512-Gkvn5mRcZCAK1EKP7hnk3VBzwqPbqpZU2AN0T08BMtvmY9Sg0C0ZqmMghJCQ3vgo+LWA38pDOPiaM8EW7BZEow==
|
integrity sha512-Gkvn5mRcZCAK1EKP7hnk3VBzwqPbqpZU2AN0T08BMtvmY9Sg0C0ZqmMghJCQ3vgo+LWA38pDOPiaM8EW7BZEow==
|
||||||
|
|
||||||
tinymce@^8.0.2:
|
"tinymce@^6.0.0 || ^5.5.1", tinymce@^6.2.0:
|
||||||
version "8.0.2"
|
version "6.8.6"
|
||||||
resolved "https://registry.yarnpkg.com/tinymce/-/tinymce-8.0.2.tgz#babaaa40c154d0832b41332f25f3485b5887a6f2"
|
resolved "https://registry.yarnpkg.com/tinymce/-/tinymce-6.8.6.tgz#799e4f03eeb4399399dfdeb12ba17b3b91887adf"
|
||||||
integrity sha512-Gkvn5mRcZCAK1EKP7hnk3VBzwqPbqpZU2AN0T08BMtvmY9Sg0C0ZqmMghJCQ3vgo+LWA38pDOPiaM8EW7BZEow==
|
integrity sha512-++XYEs8lKWvZxDCjrr8Baiw7KiikraZ5JkLMg6EdnUVNKJui0IsrAADj5MsyUeFkcEryfn2jd3p09H7REvewyg==
|
||||||
|
|
||||||
tmp-promise@^3.0.2:
|
tmp-promise@^3.0.2:
|
||||||
version "3.0.3"
|
version "3.0.3"
|
||||||
|
|||||||
Reference in New Issue
Block a user