352 lines
10 KiB
Vue
352 lines
10 KiB
Vue
<template>
|
||
<KlNavTab></KlNavTab>
|
||
<div class="mx-auto w-[1440px]">
|
||
<!-- 使用 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-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-form-item>
|
||
<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-option v-for="item in projectTypeList" :key="item.id" :label="item.name" :value="item.id" />
|
||
</el-select>
|
||
</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>
|
||
<div style="border: 1px solid #eeeeee; margin-top: 10px" class="rounded">
|
||
<WeToolbar style="border-bottom: 1px solid #eeeeee" :editor="editorRef" :defaultConfig="toolbarConfig" :mode="mode" />
|
||
|
||
<WeEditor
|
||
style="min-height: 300px; overflow-y: hidden"
|
||
v-model="valueHtml"
|
||
:defaultConfig="editorConfig"
|
||
:mode="mode"
|
||
@onCreated="handleCreated"
|
||
@onChange="handleChange"
|
||
@onDestroyed="handleDestroyed"
|
||
@onFocus="handleFocus"
|
||
@onBlur="handleBlur"
|
||
@customAlert="customAlert"
|
||
@customPaste="customPaste"
|
||
/>
|
||
</div>
|
||
<!-- 按钮区域 -->
|
||
<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 } from '@/api/upnew/index'
|
||
import { upload } from '@/api/common/index' // 自定义上传方法
|
||
import '@wangeditor/editor/dist/css/style.css' // 引入 css
|
||
// import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
|
||
import { onBeforeUnmount, shallowRef } from 'vue'
|
||
|
||
import useUserStore from '~/stores/user'
|
||
const userStore = useUserStore()
|
||
// 获取从其他地方传过来的参数
|
||
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 mode = 'default'
|
||
|
||
const isClient = ref(false)
|
||
if (import.meta.client) {
|
||
isClient.value = true
|
||
}
|
||
|
||
// 编辑器实例,必须用 shallowRef
|
||
const editorRef = shallowRef()
|
||
|
||
// 内容 HTML
|
||
const valueHtml = ref('<p></p>')
|
||
|
||
// 模拟 ajax 异步获取内容
|
||
onMounted(() => {
|
||
setTimeout(() => {
|
||
valueHtml.value = '<p></p>'
|
||
}, 1500)
|
||
})
|
||
|
||
const toolbarConfig = {}
|
||
const editorConfig = {
|
||
placeholder: '请输入内容...',
|
||
// 上传图片的配置
|
||
MENU_CONF: {
|
||
uploadImage: {
|
||
server: 'https://tuxixi.net/prod-api/app-api/infra/file/upload',
|
||
fieldName: 'file', //这个是参数名字
|
||
headers: {
|
||
//配置token 接口需要就配 不需要就不用
|
||
Authorization: `Bearer ${userStore.token}`,
|
||
},
|
||
customInsert(res: any, insertFn: any) {
|
||
// 这个是获取接口返回的数据
|
||
insertFn(res.data) // 从 res 中找到 url(也就是接口返回的图片地址),然后插入图片
|
||
},
|
||
},
|
||
uploadVideo: {
|
||
server: 'https://tuxixi.net/prod-api/app-api/infra/file/upload',
|
||
fieldName: 'file', //这个是参数名字
|
||
maxFileSize: 1200 * 1024 * 1024, // 1200M
|
||
headers: {
|
||
//配置token 接口需要就配 不需要就不用
|
||
Authorization: `Bearer ${userStore.token}`,
|
||
},
|
||
customInsert(res: any, insertFn: any) {
|
||
// 这个是获取接口返回的数据
|
||
insertFn(res.data) // 从 res 中找到 url(也就是接口返回的图片地址),然后插入图片
|
||
},
|
||
},
|
||
},
|
||
}
|
||
|
||
// 表单数据
|
||
const formData = ref({
|
||
projectDicId: undefined,
|
||
postsTags: [],
|
||
postsCover: [] as any,
|
||
postsTitle: '',
|
||
channelId: channelId || undefined,
|
||
})
|
||
|
||
const formRef = ref()
|
||
const post_loading = ref(false)
|
||
const saveContent = () => {
|
||
formRef.value.validate().then(() => {
|
||
if (!valueHtml.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: valueHtml.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
|
||
})
|
||
})
|
||
}
|
||
|
||
// 组件销毁时,也及时销毁编辑器
|
||
onBeforeUnmount(() => {
|
||
const editor = editorRef.value
|
||
if (editor == null) return
|
||
editor.destroy()
|
||
})
|
||
|
||
const handleCreated = (editor: any) => {
|
||
editorRef.value = editor // 记录 editor 实例,重要!
|
||
}
|
||
|
||
const handleChange = (editor: any) => {
|
||
console.log('change:', editor.getHtml())
|
||
}
|
||
|
||
const handleDestroyed = (editor: any) => {
|
||
console.log('destroyed', editor)
|
||
}
|
||
|
||
const handleFocus = (editor: any) => {
|
||
console.log('focus', editor)
|
||
}
|
||
|
||
const handleBlur = (editor: any) => {
|
||
console.log('blur', editor)
|
||
}
|
||
const customAlert = (info: any, type: any) => {
|
||
alert(`【自定义提示】${type} - ${info}`)
|
||
}
|
||
const customPaste = (editor: any, event: any, callback: any) => {
|
||
console.log('ClipboardEvent 粘贴事件对象', event)
|
||
// const html = event.clipboardData.getData('text/html') // 获取粘贴的 html
|
||
const text = event.clipboardData.getData('text/plain') // 获取粘贴的纯文本
|
||
// const rtf = event.clipboardData.getData('text/rtf') // 获取 rtf 数据(如从 word wsp 复制粘贴)
|
||
|
||
// 自定义插入内容
|
||
editor.insertText(text)
|
||
|
||
// 返回 false ,阻止默认粘贴行为
|
||
event.preventDefault()
|
||
callback(false) // 返回值(注意,vue 事件的返回值,不能用 return)
|
||
|
||
// 返回 true ,继续默认的粘贴行为
|
||
// callback(true)
|
||
}
|
||
|
||
/** 获取频道列表 */
|
||
const channelIdList = ref<any>([])
|
||
const getChannelIdList = () => {
|
||
list().then((res) => {
|
||
channelIdList.value = res.data
|
||
})
|
||
}
|
||
getChannelIdList()
|
||
|
||
const projectTypeList = ref<any>([])
|
||
/** 获取分类下拉框 */
|
||
const getParent = () => {
|
||
parent({
|
||
type: 1,
|
||
parentId: 0,
|
||
}).then((res) => {
|
||
projectTypeList.value = res.data
|
||
})
|
||
}
|
||
getParent()
|
||
|
||
const loading = ref(false)
|
||
/** 获取标签 */
|
||
const labelsList = ref<any>([])
|
||
const remoteMethod = (query: string) => {
|
||
if (query) {
|
||
loading.value = true
|
||
keywords({
|
||
type: 1,
|
||
keywords: query,
|
||
})
|
||
.then((res) => {
|
||
labelsList.value = res.data
|
||
})
|
||
.finally(() => {
|
||
loading.value = false
|
||
})
|
||
} else {
|
||
labelsList.value = []
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.custom-form {
|
||
border: 2px solid #eeeeee;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.upload-container {
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.cover-uploader {
|
||
:deep(.el-upload) {
|
||
width: fit-content;
|
||
}
|
||
}
|
||
|
||
.image-error {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: #909399;
|
||
height: 100%;
|
||
}
|
||
|
||
.image-actions {
|
||
display: flex;
|
||
justify-content: center;
|
||
}
|
||
|
||
:deep(.el-form-item__label) {
|
||
font-weight: normal;
|
||
}
|
||
|
||
:deep(.el-button--primary.is-link) {
|
||
padding: 0;
|
||
height: auto;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.text-gray-500 {
|
||
color: #999;
|
||
}
|
||
|
||
.text-12px {
|
||
font-size: 12px;
|
||
}
|
||
</style>
|