<template> <a-button v-if="props.isCreate" type="primary" @click="handleClick"> <template #icon><icon-plus /></template> 新建 </a-button> <a-button v-if="!props.isCreate" type="outline" size="small" :style="{ marginRight: '10px', padding: '7px' }" @click="handleClick" > <template #icon><icon-edit /></template> 修改 </a-button> <a-modal width="900px" :visible="visible" @cancel="handleCancel" > <template #title>{{ modalTitle }}</template> <a-form ref="CreateRef" :model="formData" :style="{ width: '650px' }"> <a-form-item field="title" label='标题' :validate-trigger="['change', 'input']" :rules="[ { required: true, message: '请输入标题' }, ]" > <a-input v-model="formData.title" placeholder='请输入公告标题' /> </a-form-item> <a-form-item field="top" label='置顶' :validate-trigger="['change', 'input']" > <a-switch v-model="formData.top" :checked-value="true" :unchecked-value="false" /> </a-form-item> <a-form-item field="remark" label='备注' :validate-trigger="['change', 'input']" > <!-- v-if="isCreate"--> <a-input v-model="formData.remark" placeholder='请输入备注' /> </a-form-item> <a-form-item label='附件' > <!-- v-if="isCreate"--> <a-upload v-model="formData.attachmentIds" show-file-list :custom-request="customRequest" @before-remove="beforeRemove" > <template #upload-item="{ file }"> <div style="display: flex; align-items: center;"> <img :src="file.url" alt="上传文件" style="width: 50px; height: 50px; margin-right: 10px;" /> <span>{{ file.name }}</span> </div> </template> </a-upload> </a-form-item> <a-form-item field="content" label='内容' :rules="[{ required: true}]"> <div style="border: 1px solid #ccc;min-width: 700px"> <Toolbar style="border-bottom: 1px solid #ccc" :editor="editorRef" :default-config="toolbarConfig" :mode="mode" :class="{'fullscreen-toolbar': isFullScreen}" /> <Editor v-model="formData.content" style="overflow-y: hidden;height: 200px;" :default-config="editorConfig" :mode="mode" @on-created="handleCreated" :class="{'fullscreen-editor': isFullScreen}" /> </div> <!-- <a-textarea v-model="formData.content" placeholder="请输入公告内容" style="height: 100px" />--> </a-form-item> </a-form> <template #footer> <a-button @click="handleCancel" style="position: static">取消</a-button> <a-button @click="handleSubmit" style="position: static" type="primary">确定</a-button> </template> </a-modal> </template> <script lang="ts" setup> import useVisible from '@/hooks/visible'; import { computed, defineEmits, PropType, ref, shallowRef,onBeforeUnmount } from 'vue'; import { BulletinCreateRecord } from '@/api/bulletin-mgmt'; import { FormInstance } from '@arco-design/web-vue/es/form'; import { Message } from '@arco-design/web-vue'; import { useBulletinStore } from '@/store'; import { Editor, Toolbar } from '@wangeditor/editor-for-vue'; import { IEditorConfig } from '@wangeditor/editor' import '@wangeditor/editor/dist/css/style.css' const props = defineProps({ prem: { type: Object as PropType<BulletinCreateRecord>, }, isCreate: Boolean, }); const emit = defineEmits(['refresh']); const modalTitle = computed(() => { return props.isCreate ? '新增公告' : '编辑公告'; }); const { visible, setVisible } = useVisible(false); const checkKeys = ref<number[]>([]); const CreateRef = ref<FormInstance>(); const formData = ref<any>({ ...props.prem, attachmentIds: [], }); const bulletinStore = useBulletinStore(); const editorRef = shallowRef() const isFullScreen = ref(false); const mode = 'default'; const toolbarConfig = { excludeKeys: ['uploadVideo', 'insertImage','insertVideo']} const handleCreated = (editor: any) => { editorRef.value = editor; // 记录 editor 实例,重要! // 监听全屏事件 editor.on('fullScreen', () => { }) } // 组件被点击 const handleClick = () => { setVisible(true); }; const editorConfig: Partial<IEditorConfig> = { placeholder: '请输入内容...',MENU_CONF:{ // 隐藏菜单 hide: ['code', 'table', 'emoticon', 'uploadImage', 'video', 'todo', 'specialChar'], // 配置上传图片 uploadImage: { base64LimitSize: 1024 * 1024, // server: '/api/rest/bulletin/1/add', } } } // 提交 const handleSubmit = async () => { const valid = await CreateRef.value?.validate(); if (!valid) { formData.value.permissionIds = checkKeys.value; // 新增 if (props.isCreate) { // formData.value.username = formData.value.email; const res = await bulletinStore.createBulletin(formData.value); if (res.status === 200) { Message.success({ content: '新建成功', duration: 5 * 1000, }); emit('refresh'); setVisible(false); } CreateRef.value?.resetFields(); } else { // 编辑 const res = await bulletinStore.updateBulletin(formData.value); if (res.status === 200) { Message.success({ content: '修改成功', duration: 5 * 1000, }); emit('refresh'); setVisible(false); } } } }; // 自定义文件上传 const customRequest = async (option: any) => { const { fileItem,onSuccess,onError } = option const formDataFile = new FormData(); formDataFile.append('file', fileItem.file); formDataFile.append('type', '其他'); const res = await bulletinStore.addAttachments(formDataFile); if (res.status === 200) { onSuccess(res.data); console.log(formData.value); formData.value.attachmentIds.push(res.data.id); console.log(formData.value); } else { onError(res.data); } } // 删除附件 const beforeRemove = async (file: any) => { const res = await bulletinStore.deleteAttachment(file.response.id); return res.status === 200; } // 组件销毁时,也及时销毁编辑器 onBeforeUnmount(() => { const editor = editorRef.value if (editor == null) return editor.destroy() }) // 关闭 const handleCancel = async () => { checkKeys.value = []; setVisible(false); } </script> <style scoped> .fullscreen-toolbar { position: fixed; top: 0; left: 0; width: 100%; height: 50px; /* 根据需要调整高度 */ z-index: 999; background-color: white; } .fullscreen-editor { position: fixed; top: 50px; /* 根据 toolbar 的高度调整 */ left: 0; width: 100%; height: calc(100% - 50px); /* 减去 toolbar 的高度 */ z-index: 999; background-color: white; } </style>