ContentConfig.vue 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. <!--
  2. * @since: 2024-12-30
  3. * ContentConfig.vue
  4. -->
  5. <template>
  6. <div class="container"></div>
  7. <card-layout title="内容配置" :isShowWraning="false" :mandatory="false">
  8. <el-form
  9. ref="ruleFormRef"
  10. label-width="auto"
  11. :model="ruleForm"
  12. :label-position="labelPosition"
  13. class="el-form-outer"
  14. >
  15. <el-form-item label="简介内容" prop="introduction" class="transprant">
  16. <el-input
  17. v-model="ruleForm.introduction"
  18. placeholder="请输入500字以内的简介内容"
  19. type="textarea"
  20. :rows="5"
  21. maxlength="500"
  22. show-word-limit
  23. :disabled="!pageScopedDisabled"
  24. />
  25. </el-form-item>
  26. <el-form-item label="详情内容" prop="contentType" class="transprant">
  27. <el-radio-group v-model="ruleForm.contentType" :disabled="pageScopedDisabled">
  28. <el-radio :value="item.value" v-for="item in contentTypeOptinos" :key="item.value">{{
  29. item.label
  30. }}</el-radio>
  31. </el-radio-group>
  32. </el-form-item>
  33. <el-form-item
  34. label=" "
  35. prop="contentUrl"
  36. class="transprant"
  37. v-if="ruleForm.contentType === ContentTypeEnum.LINK"
  38. >
  39. <el-input
  40. v-model="ruleForm.contentUrl"
  41. placeholder="请将链接地址粘贴到此处"
  42. :disabled="!pageScopedDisabled"
  43. />
  44. </el-form-item>
  45. <el-form-item
  46. label=" "
  47. prop="content"
  48. v-if="ruleForm.contentType === ContentTypeEnum.RICHTEXT"
  49. >
  50. <div class="editor-wrapper" style="border: 1px solid #ccc">
  51. <Toolbar
  52. style="border-bottom: 1px solid #ccc"
  53. :editor="editorRef"
  54. :defaultConfig="toolbarConfig"
  55. />
  56. <Editor
  57. id="editor"
  58. style="height: 500px; overflow-y: hidden"
  59. v-model="ruleForm.content"
  60. :defaultConfig="editorConfig"
  61. @onCreated="handleCreated"
  62. />
  63. </div>
  64. </el-form-item>
  65. <el-form-item label="操作人" prop="operator" class="transprant">
  66. <el-input v-model="ruleForm.operator" :disabled="true" />
  67. </el-form-item>
  68. </el-form>
  69. </card-layout>
  70. </template>
  71. <script setup lang="ts">
  72. import { onBeforeUnmount, ref, shallowRef, watch, computed } from 'vue';
  73. import { useRoute } from 'vue-router';
  74. import type { FormProps } from 'element-plus';
  75. import '@wangeditor/editor/dist/css/style.css'; // 引入 css
  76. import { Editor, Toolbar } from '@wangeditor/editor-for-vue';
  77. import type { IEditorConfig } from '@wangeditor/editor';
  78. import { RuleFormView, ContentTypeEnum } from './../type';
  79. import { contentTypeOptinos } from '../../constant';
  80. import CardLayout from './CardLayout.vue';
  81. import { useUserStore } from '@/store/modules/user';
  82. interface Props {
  83. dataSoure: RuleFormView;
  84. isDisabled: boolean;
  85. }
  86. const props = defineProps<Props>();
  87. const route = useRoute();
  88. const labelPosition = ref<FormProps['labelPosition']>('left');
  89. const userStore = useUserStore();
  90. const pageScopedDisabled = computed(() => props.isDisabled === false || route.query.viewModel === 'edit')
  91. /**
  92. * 表单相关操作
  93. */
  94. type Rule = Pick<
  95. RuleFormView,
  96. 'introduction' | 'contentType' | 'content' | 'operator' | 'contentUrl'
  97. >;
  98. const ruleForm = ref<Rule>({
  99. introduction: '',
  100. contentType: ContentTypeEnum.RICHTEXT,
  101. content: '',
  102. operator: '',
  103. contentUrl: '',
  104. });
  105. watch(
  106. () => props.dataSoure,
  107. (value) => {
  108. if (value) {
  109. const { introduction, contentType, content, operator, contentUrl } = value;
  110. ruleForm.value = {
  111. introduction,
  112. contentType,
  113. content,
  114. operator,
  115. contentUrl,
  116. };
  117. }
  118. },
  119. {
  120. immediate: true,
  121. deep: true,
  122. },
  123. );
  124. /********************* 富文本区域配置与方法 **********************/
  125. // 编辑器实例,必须用 shallowRef
  126. const editorRef = shallowRef();
  127. // 内容 HTML
  128. const valueHtml = ref();
  129. // 排除工具栏选项
  130. const toolbarConfig = {
  131. excludeKeys: [
  132. 'insertTable', // 插入表格
  133. 'deleteTable', // 删除表格
  134. 'insertVideo',
  135. 'uploadVideo',
  136. 'codeBlock', // 代码块
  137. 'emotion', // 表情
  138. 'fullScreen'
  139. ],
  140. };
  141. const editorConfig: Partial<IEditorConfig> = {
  142. placeholder: '请输入内容...',
  143. MENU_CONF: {},
  144. };
  145. editorConfig.MENU_CONF!['uploadImage'] = {
  146. // 上传图片的配置
  147. server: './eye_api_bak/api/systemMessage/uploadPicture', // form-data fieldName ,默认值 'wangeditor-uploaded-image'
  148. fieldName: 'file',
  149. // 单个文件的最大体积限制,默认为 2M
  150. maxFileSize: 5 * 1024 * 1024, // 1M
  151. // 最多可上传几个文件,默认为 100
  152. maxNumberOfFiles: 10,
  153. // 选择文件时的类型限制,默认为 ['image/*'] 。如不想限制,则设置为 []
  154. allowedFileTypes: ['image/*'],
  155. // 自定义上传参数。参数会被添加到 formData 中,一起上传到服务端。
  156. meta: {
  157. bizType: 'PUSH_MESSAGE',
  158. fileName: '',
  159. },
  160. // 将 meta 拼接到 url 参数中,默认 false
  161. metaWithUrl: false,
  162. // 自定义增加 http header
  163. headers: {
  164. Accept: 'application/json, text/plain, */*',
  165. // ContentType: 'application/json;charset=UTF-8'
  166. Satoken: userStore.getToken,
  167. Tenantid: userStore.getTenantId,
  168. },
  169. // 跨域是否传递 cookie ,默认为 false
  170. withCredentials: true,
  171. // 超时时间,默认为 10 秒
  172. timeout: 10 * 1000, // 5 秒
  173. // 上传之前触发
  174. onBeforeUpload(file) {
  175. return file;
  176. // 可以 return
  177. // 1. return file 或者 new 一个 file ,接下来将上传
  178. // 2. return false ,不上传这个 file
  179. },
  180. // 上传进度的回调函数
  181. onProgress(progress: number) {
  182. // progress 是 0-100 的数字
  183. },
  184. // 单个文件上传成功之后
  185. onSuccess(file: File, res: any) {
  186. },
  187. // 单个文件上传失败
  188. onFailed(file: File, res: any) {
  189. },
  190. // 上传错误,或者触发 timeout 超时
  191. onError(file: File, err: any, res: any) {
  192. },
  193. };
  194. // 执行 createEditor 组件销毁时,也及时销毁编辑器
  195. onBeforeUnmount(() => {
  196. const editor = editorRef.value;
  197. if (editor == null) return;
  198. editor.destroy();
  199. });
  200. const handleCreated = (editor) => {
  201. editorRef.value = editor // 创建富文本编辑器
  202. if(!pageScopedDisabled.value){
  203. editorRef.value.disable() //禁用
  204. } else {
  205. editorRef.value.enable() //启用
  206. }
  207. };
  208. const buildFormdata = () => {
  209. return {
  210. ...ruleForm.value,
  211. // content: valueHtml.value,
  212. };
  213. };
  214. defineExpose({ buildFormdata });
  215. </script>
  216. <style scoped lang="scss">
  217. .editor-wrapper{
  218. z-index: 90;
  219. }
  220. </style>