From 358e822660e080b41d455d4c74ce8fad48dcd970 Mon Sep 17 00:00:00 2001 From: nil Date: Wed, 17 Jul 2024 19:21:09 -0700 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=A2=98=E7=9B=AE=E4=B8=8E=E9=80=89?= =?UTF-8?q?=E9=A1=B9=E6=94=AF=E6=8C=81=E5=9B=BE=E7=89=87=20(#291)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 题目与选项支持图片 * fix: 修复使用本地存储时文件访问路径不正确的问题 * fix: 图片编辑表单无法输入 * chore: 添加上传文件夹到gitignore * fix: 两个#app的问题 --- .gitignore | 3 + nginx/nginx.conf | 6 ++ web/src/common/Editor/RichEditor.vue | 80 ++++++++++++------- web/src/common/xss.js | 10 +++ web/src/management/App.vue | 5 +- .../pages/analysis/components/DataTable.vue | 75 +++++++++++------ .../analysis/components/ImagePreview.vue | 72 +++++++++++++++++ .../pages/edit/components/MaterialGroup.vue | 1 + .../logicModule/components/ConditionView.vue | 6 +- web/src/management/styles/common.scss | 8 ++ .../EditOptions/Options/OptionEdit.vue | 1 + .../widgets/TitleModules/EditTitle/index.jsx | 1 + web/src/render/App.vue | 4 +- web/vite.config.ts | 5 ++ 14 files changed, 212 insertions(+), 65 deletions(-) create mode 100644 web/src/management/pages/analysis/components/ImagePreview.vue create mode 100644 web/src/management/styles/common.scss diff --git a/.gitignore b/.gitignore index a35571b2..4031f8b1 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,6 @@ pnpm-debug.log* *.sw? .history + +# 默认的上传文件夹 +userUpload diff --git a/nginx/nginx.conf b/nginx/nginx.conf index 34854cdf..30e5d7fc 100644 --- a/nginx/nginx.conf +++ b/nginx/nginx.conf @@ -51,6 +51,12 @@ http { location /api { proxy_pass http://127.0.0.1:3000; } + + # 静态文件的默认存储文件夹 + # 文件夹的配置在 server/src/modules/file/config/index.ts SERVER_LOCAL_CONFIG.FILE_KEY_PREFIX + location /userUpload { + proxy_pass http://127.0.0.1:3000; + } error_page 500 502 503 504 /500.html; client_max_body_size 20M; diff --git a/web/src/common/Editor/RichEditor.vue b/web/src/common/Editor/RichEditor.vue index d15b810a..c0357453 100644 --- a/web/src/common/Editor/RichEditor.vue +++ b/web/src/common/Editor/RichEditor.vue @@ -1,24 +1,9 @@ @@ -26,28 +11,62 @@ import '@wangeditor/editor/dist/css/style.css' import './styles/reset-wangeditor.scss' import { Editor, Toolbar } from '@wangeditor/editor-for-vue' -import { ref, shallowRef, onBeforeMount, watch } from 'vue' +import { ref, shallowRef, onBeforeMount, watch, computed } from 'vue' +import { useStore } from 'vuex' +import { get as _get } from 'lodash-es' const emit = defineEmits(['input', 'onFocus', 'change', 'blur', 'created']) const model = defineModel() -const props = defineProps(['staticToolBar']) +const props = defineProps({ + staticToolBar: { default: false, required: false }, + needUploadImage: { default: false, required: false } +}) const curValue = ref('') const editorRef = shallowRef() -const showToolbar = ref(props.staticToolBar || false) +const showToolbar = ref(props.staticToolBar) const mode = 'simple' -const toolbarConfig = { - toolbarKeys: [ - 'color', // 字体色 - 'bgColor', // 背景色 - 'bold', - 'insertLink' // 链接 - ] +const toolbarConfig = computed(() => { + const config = { + toolbarKeys: [ + 'color', // 字体色 + 'bgColor', // 背景色 + 'bold', + 'insertLink', // 链接 + ] + } + if (props.needUploadImage) { + config.toolbarKeys.push('uploadImage') + } + + return config +}) + +const editorConfig = { + MENU_CONF: {} } -const editorConfig = {} +const store = useStore() +const token = _get(store, 'state.user.userInfo.token') + +editorConfig.MENU_CONF['uploadImage'] = { + allowedFileTypes: ['image/jpeg', 'image/png'], + server: '/api/file/upload', + fieldName: 'file', + meta: { + //! 此处的channel需要跟上传接口内配置的channel一致 + channel: 'upload' + }, + headers: { + Authorization: `Bearer ${token}` + }, + customInsert(res, insertFn) { + const url = res.data.url + insertFn(url, '', '') + }, +} const setHtml = (newHtml) => { const editor = editorRef.value @@ -114,6 +133,7 @@ onBeforeMount(() => { .static-toolbar { border-bottom: 1px solid #dedede; } + .dynamic-toolbar { position: absolute; left: 0; diff --git a/web/src/common/xss.js b/web/src/common/xss.js index e12e20ff..d4d71e8b 100644 --- a/web/src/common/xss.js +++ b/web/src/common/xss.js @@ -27,6 +27,16 @@ const isVideo = (html) => { return html.indexOf(' -1 } +export const cleanRichTextWithMediaTag = (text) => { + if (!text) { + return text === 0 ? 0 : '' + } + const html = transformHtmlTag(text).replace(//g,'[图片]').replace(//g,'[视频]') + const content = html.replace(/<[^<>]+>/g, '').replace(/ /g, '') + + return content +} + export const cleanRichText = (text) => { if (!text) { return text === 0 ? 0 : '' diff --git a/web/src/management/App.vue b/web/src/management/App.vue index 545876c4..cc283ad9 100644 --- a/web/src/management/App.vue +++ b/web/src/management/App.vue @@ -1,7 +1,5 @@ + diff --git a/web/src/management/pages/analysis/components/ImagePreview.vue b/web/src/management/pages/analysis/components/ImagePreview.vue new file mode 100644 index 00000000..5b160210 --- /dev/null +++ b/web/src/management/pages/analysis/components/ImagePreview.vue @@ -0,0 +1,72 @@ + + + \ No newline at end of file diff --git a/web/src/management/pages/edit/components/MaterialGroup.vue b/web/src/management/pages/edit/components/MaterialGroup.vue index f59932ab..fe6f2886 100644 --- a/web/src/management/pages/edit/components/MaterialGroup.vue +++ b/web/src/management/pages/edit/components/MaterialGroup.vue @@ -3,6 +3,7 @@ v-model="renderData" handle=".question-wrapper.isSelected" filter=".question-wrapper.isSelected .question.isSelected" + :preventOnFilter="false" :group="DND_GROUP" :onEnd="checkEnd" :move="checkMove" diff --git a/web/src/management/pages/edit/modules/logicModule/components/ConditionView.vue b/web/src/management/pages/edit/modules/logicModule/components/ConditionView.vue index 01065654..ae98af75 100644 --- a/web/src/management/pages/edit/modules/logicModule/components/ConditionView.vue +++ b/web/src/management/pages/edit/modules/logicModule/components/ConditionView.vue @@ -57,7 +57,7 @@ import { computed, inject, ref, type ComputedRef } from 'vue' import { ConditionNode, RuleNode } from '@/common/logicEngine/RuleBuild' import { CHOICES } from '@/common/typeEnum' -import { cleanRichText } from '@/common/xss' +import { cleanRichTextWithMediaTag } from '@/common/xss' const renderData = inject>>('renderData') || ref([]) const props = defineProps({ index: { @@ -88,7 +88,7 @@ const fieldList = computed(() => { .filter((question: any) => CHOICES.includes(question.type)) .map((item: any) => { return { - label: `${item.showIndex ? item.indexNumber + '.' : ''} ${cleanRichText(item.title)}`, + label: `${item.showIndex ? item.indexNumber + '.' : ''} ${cleanRichTextWithMediaTag(item.title)}`, value: item.field } }) @@ -102,7 +102,7 @@ const getRelyOptions = computed(() => { return ( currentQuestion?.options.map((item: any) => { return { - label: cleanRichText(item.text), + label: cleanRichTextWithMediaTag(item.text), value: item.hash } }) || [] diff --git a/web/src/management/styles/common.scss b/web/src/management/styles/common.scss new file mode 100644 index 00000000..1ad8d701 --- /dev/null +++ b/web/src/management/styles/common.scss @@ -0,0 +1,8 @@ +// 富文本标题、选项中的预览弹窗的图片宽度 +.el-popover { + p { + img { + max-width: 100%; + } + } + } \ No newline at end of file diff --git a/web/src/materials/questions/widgets/EditOptions/Options/OptionEdit.vue b/web/src/materials/questions/widgets/EditOptions/Options/OptionEdit.vue index 8025a528..0fa44cf9 100644 --- a/web/src/materials/questions/widgets/EditOptions/Options/OptionEdit.vue +++ b/web/src/materials/questions/widgets/EditOptions/Options/OptionEdit.vue @@ -12,6 +12,7 @@
diff --git a/web/src/materials/questions/widgets/TitleModules/EditTitle/index.jsx b/web/src/materials/questions/widgets/TitleModules/EditTitle/index.jsx index 598c9b00..dd4ecf5a 100644 --- a/web/src/materials/questions/widgets/TitleModules/EditTitle/index.jsx +++ b/web/src/materials/questions/widgets/TitleModules/EditTitle/index.jsx @@ -69,6 +69,7 @@ export default defineComponent({ { editor?.focus() diff --git a/web/src/render/App.vue b/web/src/render/App.vue index c4f914ea..acafc152 100644 --- a/web/src/render/App.vue +++ b/web/src/render/App.vue @@ -1,7 +1,5 @@