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 @@