<!-- 新增通知公告弹窗 -->
<script lang="ts" setup name="addNotice">
import type { FormInstance, FormRules } from 'element-plus'
import { ElMessage } from 'element-plus'
import dayjs from 'dayjs'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import { addNoticeApi, getNoticeDetail, updateNoticeApi, uploadApi } from '@/api/system/notice'
import { getPhotoUrl } from '@/api/system/tool'
import useUserStore from '@/store/modules/user'
import '@wangeditor/editor/dist/css/style.css' // 引入 css
const emits = defineEmits(['resetData'])
const userInfo = useUserStore()
const title = ref('')
const ruleFormRef = ref<FormInstance>() // from组件
const ruleForm = reactive({
noticeNo: '', // 通知公告编号
noticePublisher: '', // 发布人
noticeCompany: '', // 发布单位
noticeTime: '', // 发布时间
noticeSketch: '', // 内容简述
noticeContent: '', // 发布内容
minioFileName: '', // 上传文件名
noticeTitle: '', // 标题
id: '',
}) // 表单
const rules = ref<FormRules>({
noticeTitle: [{ required: true, message: '标题必填', trigger: 'blur' }],
noticeSketch: [{ required: true, message: '内容简述必填', trigger: 'blur' }],
noticeContent: [{ required: true, message: '发布内容必填', trigger: 'blur' }],
}) // 表单验证规则
const dialogVisible = ref<boolean>(false) // 弹窗显示
// 重置
const resetDialog = () => {
ruleForm.noticeTime = ''
ruleForm.noticeSketch = ''
ruleForm.noticeContent = ''
ruleForm.minioFileName = ''
ruleForm.noticeTitle = ''
}
// 弹窗初始化
const initDialog = (row: any) => {
dialogVisible.value = true
title.value = row.title
if (row.title === '新建') {
ruleForm.noticePublisher = userInfo.$state.name
ruleForm.noticeCompany = userInfo.$state.deptName
ruleForm.noticeTime = dayjs().format('YYYY-MM-DD HH:mm:ss')
resetDialog()
}
else {
// 获取详情信息
getNoticeDetail({
noticeNo: row.noticeNo,
noticePublisher: row.noticePublisher,
noticeTitle: row.noticeTitle,
noticeEndTime: '',
noticeStartTime: '',
}).then((res) => {
if (res.code === 200 && res.data.rows.length) {
ruleForm.noticeNo = res.data.rows[0].noticeNo
ruleForm.noticePublisher = res.data.rows[0].noticePublisher
ruleForm.noticeCompany = res.data.rows[0].noticeCompany
ruleForm.noticeTime = res.data.rows[0].noticeTime
ruleForm.noticeSketch = res.data.rows[0].noticeSketch
ruleForm.noticeContent = res.data.rows[0].noticeContent
ruleForm.minioFileName = res.data.rows[0].minioFileName
ruleForm.noticeTitle = res.data.rows[0].noticeTitle
ruleForm.id = res.data.rows[0].id
}
})
}
}
defineExpose({ initDialog })
// 关闭弹窗
const close = () => {
resetDialog()
dialogVisible.value = false
emits('resetData')
}
// 提交
const submitForm = async (formEl: FormInstance | undefined) => {
console.log(ruleForm.noticeContent)
if (!formEl) { return }
await formEl.validate((valid, fields) => {
if (valid) {
ruleForm.noticeTime = dayjs().format('YYYY-MM-DD HH:mm:ss')
if (title.value === '新建') {
addNoticeApi(ruleForm).then((res) => {
if (res.code === 200) {
close()
ElMessage.success('操作成功')
}
else {
ElMessage.warning(res.message)
}
})
}
else {
updateNoticeApi(ruleForm).then((res) => {
if (res.code === 200) {
close()
ElMessage.success('操作成功')
}
else {
ElMessage.warning(res.message)
}
})
}
}
})
}
// 取消
const resetForm = (formEl: FormInstance | undefined) => {
// if (!formEl) { return }
formEl?.resetFields()
resetDialog()
dialogVisible.value = false
emits('resetData')
}
const fileRef = ref() // 文件上传input
const onFileChange = (event: any) => {
// 原生上传图片
// console.log(event.target.files)
// if (event.target.files[0].type === 'application/pdf') {
if (event.target.files?.length !== 0) {
// 创建formdata对象
const fd = new FormData()
fd.append('multipartFile', event.target.files[0])
uploadApi(fd).then((res) => {
if (res.code === 200) {
ruleForm.minioFileName = res.data[0]
ElMessage.success('上传成功')
}
else {
ElMessage.warning(res.message)
}
})
}
// }
// else {
// ElMessage.error('请上传pdf格式')
// }
}
const upload = () => {
fileRef.value.click()
}
// 富文本实例对象
const editorRef = shallowRef()
// 菜单配置
const toolbarConfig = {
/* 工具栏配置 */
toolbarKeys: [
'bold',
'underline',
'italic',
'clearStyle',
'color',
'bgColor',
'|',
// 菜单组,包含多个菜单
// {
// key: 'group-link',
// title: '链接',
// menuKeys: ['insertLink', 'editLink', 'unLink', 'viewLink'],
// },
'fontSize',
'fontFamily',
'lineHeight',
{
key: 'group-justify',
title: '对齐',
iconSvg: '<svg viewBox="0 0 1024 1024"><path d="M768 793.6v102.4H51.2v-102.4h716.8z m204.8-230.4v102.4H51.2v-102.4h921.6z m-204.8-230.4v102.4H51.2v-102.4h716.8zM972.8 102.4v102.4H51.2V102.4h921.6z"></path></svg>',
menuKeys: [
'justifyLeft',
'justifyRight',
'justifyCenter',
'justifyJustify',
],
},
{
key: 'group-indent',
title: '缩进',
iconSvg: '<svg viewBox="0 0 1024 1024"><path d="M0 64h1024v128H0z m384 192h640v128H384z m0 192h640v128H384z m0 192h640v128H384zM0 832h1024v128H0z m0-128V320l256 192z"></path></svg>',
menuKeys: [
'indent',
'delIndent',
],
},
{
key: 'group-more-style',
title: '更多',
iconSvg: '<svg viewBox="0 0 1024 1024"><path d="M204.8 505.6m-76.8 0a76.8 76.8 0 1 0 153.6 0 76.8 76.8 0 1 0-153.6 0Z"></path><path d="M505.6 505.6m-76.8 0a76.8 76.8 0 1 0 153.6 0 76.8 76.8 0 1 0-153.6 0Z"></path><path d="M806.4 505.6m-76.8 0a76.8 76.8 0 1 0 153.6 0 76.8 76.8 0 1 0-153.6 0Z"></path></svg>',
menuKeys: [
'through',
'code',
'sup',
'sub',
'clearStyle',
],
},
'|',
'bulletedList',
'numberedList',
'todo',
{
key: 'group-table',
title: '表格',
menuKeys: ['insertTable',
'deleteTable',
'insertTableRow',
'deleteTableRow',
'insertTableCol',
'deleteTableCol',
'tableHeader',
'tableFullWidth'],
},
'divider',
// 'emotion', 表情
'blockquote',
'headerSelect',
'redo',
'undo',
'fullScreen',
],
}
// 编辑器配置
const editorConfig = ref({
placeholder: '请输入内容...',
MENU_CONF: {
// 配置上传图片
uploadImage: {
server: 'http://111.198.10.15:21409/minio/file/upload', // 配置图片上传地址
maxFileSize: 2 * 1024 * 1024, // 10M 图片大小限制
fieldName: 'multipartFile', // 上传名字
allowedFileTypes: [], // 选择文件时的类型限制,默认为 ['image/*'] 。如不想限制,则设置为 []
// 自定义上传参数,传递图片时需要带一些参数过去写在这。参数会被添加到 formData 中,一起上传到服务端。
// meta: {
// image_class_id: "2",
// file_type: "1",
// },
// 自定义设置请求头,比如添加token之类的
// headers: {
// Accept: 'text/x-json',
// otherKey: 'xxx'
// },
// 上传进度的回调函数,可以用来显示进度条
onProgress(progress: any) {
// progress 是 0-100 的数字
console.log('progress', progress)
},
// // 单个文件上传成功之后
// onSuccess(file, res) {
// console.log(`${file.name} 上传成功`, res)
// },
// 单个文件上传失败
onFailed(file: any, res: any) {
console.log(`${file.name} 上传失败`, res)
},
// 上传错误,或者触发 timeout 超时
onError(file: any, err: any, res: any) {
console.log(`${file.name} 上传出错`, err, res)
},
// 插入图片到富文本编辑器回显
customInsert(res: any, insertFn: any) {
console.log()
// res 即服务端的返回结果
getPhotoUrl(res.data[0]).then((res) => {
const url = res.data
const alt = ''
const href = res.data
// 从 res 中找到 url alt href ,然后插入图片
insertFn(url, alt, href)
})
},
},
// 配置上传视频
uploadVideo: {
server: 'http://111.198.10.15:21409/minio/file/upload', // 配置视频上传地址
maxFileSize: 5 * 1024 * 1024, // 5M 视频大小限制
fieldName: 'multipartFile', // 上传名字
// 最多可上传几个文件,默认为 5
// maxNumberOfFiles: 1,
allowedFileTypes: [], // 选择文件时的类型限制,默认为 ['video/*'] 。如不想限制,则设置为 []
// 自定义上传参数,传递图片时需要带一些参数过去写在这。参数会被添加到 formData 中,一起上传到服务端。
// meta: {
// type: 1,
// },
// 自定义设置请求头,比如添加token之类的
// headers: {
// Accept: 'text/x-json',
// otherKey: 'xxx'
// },
// metaWithUrl: false, // 将 meta 拼接到 url 参数中,默认 false
// withCredentials: true, // 跨域是否传递 cookie ,默认为 false
// 上传之前触发
onBeforeUpload(file: any) {
// file 选中的文件,格式如 { key: file }
return file
// 可以 return
// 1. return file 或者 new 一个 file ,接下来将上传
// 2. return false ,不上传这个 file
},
// 上传进度的回调函数,可以用来显示进度条
onProgress(progress: any) {
// progress 是 0-100 的数字
console.log('progress', progress)
},
// // 单个文件上传成功之后
onSuccess(file: any, res: any) {
console.log(`${file.name} 上传成功`, res)
},
// 单个文件上传失败
onFailed(file: any, res: any) {
console.log(`${file.name} 上传失败`, res)
},
// 上传错误,或者触发 timeout 超时
onError(file: any, err: any, res: any) {
console.log(`${file.name} 上传出错`, err, res)
},
// 插入图片到富文本编辑器回显
customInsert(res: any, insertFn: any) {
console.log(res, '视频插入')
// res 即服务端的返回结果
// let url = res.data.url;
// let poster = res.data.poster;
// 从 res 中找到 url poster ,然后插入
// 参数url是视频地址,poster是视频封面图片,后端如果不返回,可以考虑写死一个固定的封面图
getPhotoUrl(res.data[0]).then((res) => {
const url = res.data
// 从 res 中找到 url alt href ,然后插入图片
insertFn(url, '')
})
},
},
},
})
const onCreated = (editor: any) => {
editorRef.value = editor
nextTick(() => {
editorRef.value = editor // 一定要用 Object.seal() ,否则会报错
})
}
const minioFileUrl = ref('')
watch(() => ruleForm.minioFileName, (newVal) => {
if (newVal) {
getPhotoUrl(newVal).then((res) => {
minioFileUrl.value = res.data
})
}
})
</script>
<template>
<el-dialog v-if="dialogVisible" v-model="dialogVisible" :title="title" width="65%" append-to-body class="container">
<el-form ref="ruleFormRef" :model="ruleForm" :rules="rules" label-position="right" label-width="110px">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="通知公告编号" prop="noticeNo">
<el-input v-model.trim="ruleForm.noticeNo" placeholder="系统自动生成" disabled />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="发布人" prop="noticePublisher">
<el-input v-model.trim="ruleForm.noticePublisher" disabled />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="发布单位" prop="noticeCompany">
<el-input v-model.trim="ruleForm.noticeCompany" disabled />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="发布时间" prop="noticeTime">
<el-input v-model.trim="ruleForm.noticeTime" disabled />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="标题" prop="noticeTitle">
<el-input v-model.trim="ruleForm.noticeTitle" />
</el-form-item>
<el-form-item label="内容简述" prop="noticeSketch">
<el-input v-model.trim="ruleForm.noticeSketch" />
</el-form-item>
<el-form-item label="附件" prop="minioFileName">
<el-link v-if="ruleForm.minioFileName" :href="minioFileUrl" type="primary" target="_blank">
{{ ruleForm.minioFileName }}
</el-link>
<el-button type="primary" :style="{ 'margin-left': ruleForm.minioFileName === '' ? '0px' : '20px' }" @click="upload">
{{ ruleForm.minioFileName === '' ? '上传' : '更换附件' }}
</el-button>
<input v-show="false" ref="fileRef" type="file" accept="pdf/*" @change="onFileChange">
</el-form-item>
<el-form-item label="发布内容" prop="noticeContent">
<div style="border: 1px solid #dcdfe6;width: 100%;border-radius: 4px;">
<toolbar
style="border-bottom: 1px solid #dcdfe6;width: 100%;border-radius: 4px;"
:editor="editorRef"
:default-config="toolbarConfig"
mode="default"
/>
<editor
v-model="ruleForm.noticeContent"
style="height: 300px; overflow-y: hidden;"
:default-config="editorConfig"
mode="default"
@onCreated="onCreated"
/>
</div>
<!-- <el-input v-model.trim="ruleForm.noticeContent" :rows="4" type="textarea" /> -->
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer footer">
<el-button type="primary" @click="submitForm(ruleFormRef)">
发布
</el-button>
<el-button @click="resetForm(ruleFormRef)">
关闭
</el-button>
</div>
</template>
</el-dialog>
</template>
<style lang="scss" scoped>
.container {
::v-deep {
.w-e-bar {
padding: 0;
.w-e-bar-item {
padding: 0;
height: 30px;
}
.w-e-bar-divider {
margin: 0;
display: none;
width: 0;
height: 0;
}
}
}
}
</style>