Merge branch 'dev' of https://gitee.com/xlsea/ruoyi-plus-soybean into dev
This commit is contained in:
+2
-1
@@ -66,8 +66,9 @@
|
|||||||
"@sa/materials": "workspace:*",
|
"@sa/materials": "workspace:*",
|
||||||
"@sa/utils": "workspace:*",
|
"@sa/utils": "workspace:*",
|
||||||
"@types/streamsaver": "^2.0.5",
|
"@types/streamsaver": "^2.0.5",
|
||||||
"@umoteam/editor": "^9.0.1",
|
|
||||||
"@vueuse/core": "14.1.0",
|
"@vueuse/core": "14.1.0",
|
||||||
|
"@wangeditor-next/editor": "^5.6.49",
|
||||||
|
"@wangeditor-next/editor-for-vue": "^5.1.14",
|
||||||
"clipboard": "2.0.11",
|
"clipboard": "2.0.11",
|
||||||
"dayjs": "1.11.19",
|
"dayjs": "1.11.19",
|
||||||
"defu": "6.1.4",
|
"defu": "6.1.4",
|
||||||
|
|||||||
Generated
+581
-2641
File diff suppressed because it is too large
Load Diff
@@ -1,104 +0,0 @@
|
|||||||
<script lang="ts" setup>
|
|
||||||
import { nextTick, ref, useAttrs, watch } from 'vue';
|
|
||||||
import type { UmoEditorOptions } from '@umoteam/editor';
|
|
||||||
import { UmoEditor } from '@umoteam/editor';
|
|
||||||
import { fetchBatchDeleteOss, fetchUploadFile } from '@/service/api/system/oss';
|
|
||||||
import { useAppStore } from '@/store/modules/app';
|
|
||||||
import { useThemeStore } from '@/store/modules/theme';
|
|
||||||
|
|
||||||
defineOptions({
|
|
||||||
name: 'UmoDocEditor'
|
|
||||||
});
|
|
||||||
|
|
||||||
const attrs: UmoEditorOptions = useAttrs();
|
|
||||||
const appStore = useAppStore();
|
|
||||||
const themeStore = useThemeStore();
|
|
||||||
const umoEditorRef = ref<InstanceType<typeof UmoEditor>>();
|
|
||||||
const isSave = ref(false);
|
|
||||||
|
|
||||||
const value = defineModel<string>('value', { required: true, default: '' });
|
|
||||||
|
|
||||||
watch(
|
|
||||||
value,
|
|
||||||
() => {
|
|
||||||
nextTick(() => {
|
|
||||||
if (isSave.value) {
|
|
||||||
isSave.value = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
umoEditorRef.value?.setContent(value.value);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
{
|
|
||||||
immediate: true
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => appStore.locale,
|
|
||||||
() => {
|
|
||||||
umoEditorRef.value?.setLocale(appStore.locale);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
async function handleSave(content: { html: string }) {
|
|
||||||
isSave.value = true;
|
|
||||||
value.value = content.html;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleFileUpload(file: File) {
|
|
||||||
const { error, data } = await fetchUploadFile(file);
|
|
||||||
if (error) throw new Error(error.message || '上传失败');
|
|
||||||
|
|
||||||
return {
|
|
||||||
id: data.ossId,
|
|
||||||
url: data.url
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleFileDelete(id: CommonType.IdType) {
|
|
||||||
window.$dialog?.warning({
|
|
||||||
title: '确认删除文件?',
|
|
||||||
content: '文件删除后不可恢复,请确认是否删除!',
|
|
||||||
positiveText: '确认删除',
|
|
||||||
negativeText: '取消',
|
|
||||||
onPositiveClick: async () => {
|
|
||||||
const { error } = await fetchBatchDeleteOss([id]);
|
|
||||||
if (error) throw new Error(error.message || '文件删除失败');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
defineExpose({
|
|
||||||
saveContent: () => umoEditorRef.value?.saveContent()
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="umo-editor size-full">
|
|
||||||
<UmoEditor
|
|
||||||
v-bind="attrs"
|
|
||||||
ref="umoEditorRef"
|
|
||||||
:theme="themeStore.darkMode ? 'dark' : 'light'"
|
|
||||||
@save="handleSave"
|
|
||||||
@file-upload="handleFileUpload"
|
|
||||||
@file-delete="handleFileDelete"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
body .flex-center {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.umo-editor .flex-center {
|
|
||||||
display: inherit !important;
|
|
||||||
align-items: inherit !important;
|
|
||||||
justify-content: inherit !important;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { onBeforeUnmount, shallowRef, watch } from 'vue';
|
||||||
|
import '@wangeditor-next/editor/dist/css/style.css';
|
||||||
|
import { Editor, Toolbar } from '@wangeditor-next/editor-for-vue';
|
||||||
|
import { i18nChangeLanguage } from '@wangeditor-next/editor';
|
||||||
|
import type { IDomEditor, IEditorConfig, IToolbarConfig } from '@wangeditor-next/editor';
|
||||||
|
import { useAppStore } from '@/store/modules/app';
|
||||||
|
import { getToken } from '@/store/modules/auth/shared';
|
||||||
|
import { getServiceBaseURL } from '@/utils/service';
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: 'WangEditor'
|
||||||
|
});
|
||||||
|
|
||||||
|
const appStore = useAppStore();
|
||||||
|
|
||||||
|
const editorRef = shallowRef<IDomEditor>();
|
||||||
|
|
||||||
|
const value = defineModel<string>('value', { required: true, default: '' });
|
||||||
|
|
||||||
|
type InsertFnType = (url: string, alt?: string, href?: string) => void;
|
||||||
|
|
||||||
|
const toolbarConfig: Partial<IToolbarConfig> = {};
|
||||||
|
|
||||||
|
const isHttpProxy = import.meta.env.DEV && import.meta.env.VITE_HTTP_PROXY === 'Y';
|
||||||
|
const { baseURL } = getServiceBaseURL(import.meta.env, isHttpProxy);
|
||||||
|
|
||||||
|
const editorConfig: Partial<IEditorConfig> = {
|
||||||
|
placeholder: '请输入内容...',
|
||||||
|
MENU_CONF: {
|
||||||
|
uploadImage: {
|
||||||
|
server: `${baseURL}/resource/oss/upload`,
|
||||||
|
fieldName: 'file',
|
||||||
|
meta: {},
|
||||||
|
headers: {
|
||||||
|
// @ts-expect-error ignore this type error
|
||||||
|
Authorization: `Bearer ${getToken()}`,
|
||||||
|
clientid: import.meta.env.VITE_APP_CLIENT_ID!
|
||||||
|
},
|
||||||
|
metaWithUrl: false,
|
||||||
|
allowedFileTypes: ['image/*'],
|
||||||
|
customInsert(res: any, insertFn: InsertFnType) {
|
||||||
|
if (String(res?.code) !== '200') {
|
||||||
|
window.$message?.error(res?.msg || res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
insertFn(res.data?.url, res.data?.fieldName);
|
||||||
|
},
|
||||||
|
onSuccess() {},
|
||||||
|
onFailed() {},
|
||||||
|
onError() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCreated = (editor: IDomEditor) => {
|
||||||
|
editorRef.value = editor;
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => appStore.locale,
|
||||||
|
() => {
|
||||||
|
const localeMap = {
|
||||||
|
'zh-CN': 'zh-CN',
|
||||||
|
'en-US': 'en'
|
||||||
|
};
|
||||||
|
i18nChangeLanguage(localeMap[appStore.locale]);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
const editor = editorRef.value;
|
||||||
|
if (editor === null) return;
|
||||||
|
|
||||||
|
editorRef.value?.destroy();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<NCard size="small" class="size-full min-h-500px" content-class="size-full">
|
||||||
|
<Toolbar :editor="editorRef" :default-config="toolbarConfig" class="border-b-1px border-gray-200" />
|
||||||
|
<Editor v-model="value" :default-config="editorConfig" @on-created="handleCreated" />
|
||||||
|
</NCard>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
:deep(.w-e-toolbar) {
|
||||||
|
background: inherit !important;
|
||||||
|
border-color: #999 !important;
|
||||||
|
}
|
||||||
|
:deep(.w-e-text-container) {
|
||||||
|
background: inherit;
|
||||||
|
border-color: #999 !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Vendored
+2
-4
@@ -16,7 +16,6 @@ declare module 'vue' {
|
|||||||
BetterScroll: typeof import('./../components/custom/better-scroll.vue')['default']
|
BetterScroll: typeof import('./../components/custom/better-scroll.vue')['default']
|
||||||
BooleanTag: typeof import('./../components/custom/boolean-tag.vue')['default']
|
BooleanTag: typeof import('./../components/custom/boolean-tag.vue')['default']
|
||||||
ButtonIcon: typeof import('./../components/custom/button-icon.vue')['default']
|
ButtonIcon: typeof import('./../components/custom/button-icon.vue')['default']
|
||||||
copy: typeof import('./../components/custom/dict-radio copy.vue')['default']
|
|
||||||
CountTo: typeof import('./../components/custom/count-to.vue')['default']
|
CountTo: typeof import('./../components/custom/count-to.vue')['default']
|
||||||
DarkModeContainer: typeof import('./../components/common/dark-mode-container.vue')['default']
|
DarkModeContainer: typeof import('./../components/common/dark-mode-container.vue')['default']
|
||||||
DataTable: typeof import('./../components/common/data-table.vue')['default']
|
DataTable: typeof import('./../components/common/data-table.vue')['default']
|
||||||
@@ -154,8 +153,8 @@ declare module 'vue' {
|
|||||||
TableSiderLayout: typeof import('./../components/advanced/table-sider-layout.vue')['default']
|
TableSiderLayout: typeof import('./../components/advanced/table-sider-layout.vue')['default']
|
||||||
TenantSelect: typeof import('./../components/custom/tenant-select.vue')['default']
|
TenantSelect: typeof import('./../components/custom/tenant-select.vue')['default']
|
||||||
ThemeSchemaSwitch: typeof import('./../components/common/theme-schema-switch.vue')['default']
|
ThemeSchemaSwitch: typeof import('./../components/common/theme-schema-switch.vue')['default']
|
||||||
UmoDocEditor: typeof import('./../components/custom/umo-doc-editor.vue')['default']
|
|
||||||
UserSelect: typeof import('./../components/custom/user-select.vue')['default']
|
UserSelect: typeof import('./../components/custom/user-select.vue')['default']
|
||||||
|
WangEditor: typeof import('./../components/custom/wang-editor.vue')['default']
|
||||||
WaveBg: typeof import('./../components/custom/wave-bg.vue')['default']
|
WaveBg: typeof import('./../components/custom/wave-bg.vue')['default']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -166,7 +165,6 @@ declare global {
|
|||||||
const BetterScroll: typeof import('./../components/custom/better-scroll.vue')['default']
|
const BetterScroll: typeof import('./../components/custom/better-scroll.vue')['default']
|
||||||
const BooleanTag: typeof import('./../components/custom/boolean-tag.vue')['default']
|
const BooleanTag: typeof import('./../components/custom/boolean-tag.vue')['default']
|
||||||
const ButtonIcon: typeof import('./../components/custom/button-icon.vue')['default']
|
const ButtonIcon: typeof import('./../components/custom/button-icon.vue')['default']
|
||||||
const copy: typeof import('./../components/custom/dict-radio copy.vue')['default']
|
|
||||||
const CountTo: typeof import('./../components/custom/count-to.vue')['default']
|
const CountTo: typeof import('./../components/custom/count-to.vue')['default']
|
||||||
const DarkModeContainer: typeof import('./../components/common/dark-mode-container.vue')['default']
|
const DarkModeContainer: typeof import('./../components/common/dark-mode-container.vue')['default']
|
||||||
const DataTable: typeof import('./../components/common/data-table.vue')['default']
|
const DataTable: typeof import('./../components/common/data-table.vue')['default']
|
||||||
@@ -304,7 +302,7 @@ declare global {
|
|||||||
const TableSiderLayout: typeof import('./../components/advanced/table-sider-layout.vue')['default']
|
const TableSiderLayout: typeof import('./../components/advanced/table-sider-layout.vue')['default']
|
||||||
const TenantSelect: typeof import('./../components/custom/tenant-select.vue')['default']
|
const TenantSelect: typeof import('./../components/custom/tenant-select.vue')['default']
|
||||||
const ThemeSchemaSwitch: typeof import('./../components/common/theme-schema-switch.vue')['default']
|
const ThemeSchemaSwitch: typeof import('./../components/common/theme-schema-switch.vue')['default']
|
||||||
const UmoDocEditor: typeof import('./../components/custom/umo-doc-editor.vue')['default']
|
|
||||||
const UserSelect: typeof import('./../components/custom/user-select.vue')['default']
|
const UserSelect: typeof import('./../components/custom/user-select.vue')['default']
|
||||||
|
const WangEditor: typeof import('./../components/custom/wang-editor.vue')['default']
|
||||||
const WaveBg: typeof import('./../components/custom/wave-bg.vue')['default']
|
const WaveBg: typeof import('./../components/custom/wave-bg.vue')['default']
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, ref, watch } from 'vue';
|
import { computed, ref, watch } from 'vue';
|
||||||
import { jsonClone } from '@sa/utils';
|
import { jsonClone } from '@sa/utils';
|
||||||
import type { UmoEditor } from '@umoteam/editor';
|
|
||||||
import { fetchCreateNotice, fetchUpdateNotice } from '@/service/api/system/notice';
|
import { fetchCreateNotice, fetchUpdateNotice } from '@/service/api/system/notice';
|
||||||
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
|
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
|
||||||
import { $t } from '@/locales';
|
import { $t } from '@/locales';
|
||||||
@@ -29,7 +28,6 @@ const visible = defineModel<boolean>('visible', {
|
|||||||
default: false
|
default: false
|
||||||
});
|
});
|
||||||
|
|
||||||
const umoEditorRef = ref<InstanceType<typeof UmoEditor>>();
|
|
||||||
const { formRef, validate, restoreValidation } = useNaiveForm();
|
const { formRef, validate, restoreValidation } = useNaiveForm();
|
||||||
const { createRequiredRule } = useFormRules();
|
const { createRequiredRule } = useFormRules();
|
||||||
|
|
||||||
@@ -77,7 +75,7 @@ function closeDrawer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function handleSubmit() {
|
async function handleSubmit() {
|
||||||
umoEditorRef.value?.saveContent();
|
// umoEditorRef.value?.saveContent();
|
||||||
await validate();
|
await validate();
|
||||||
|
|
||||||
const { noticeId, noticeTitle, noticeType, noticeContent, status } = model.value;
|
const { noticeId, noticeTitle, noticeType, noticeContent, status } = model.value;
|
||||||
@@ -112,7 +110,7 @@ watch(visible, () => {
|
|||||||
:trap-focus="false"
|
:trap-focus="false"
|
||||||
:title="title"
|
:title="title"
|
||||||
display-directive="show"
|
display-directive="show"
|
||||||
:width="1000"
|
:width="1500"
|
||||||
class="max-w-90%"
|
class="max-w-90%"
|
||||||
>
|
>
|
||||||
<NDrawerContent :title="title" :native-scrollbar="false" closable>
|
<NDrawerContent :title="title" :native-scrollbar="false" closable>
|
||||||
@@ -129,7 +127,7 @@ watch(visible, () => {
|
|||||||
</NFormItem>
|
</NFormItem>
|
||||||
</div>
|
</div>
|
||||||
<NFormItem :show-label="false" path="noticeContent">
|
<NFormItem :show-label="false" path="noticeContent">
|
||||||
<UmoDocEditor ref="umoEditorRef" v-model:value="model.noticeContent!" />
|
<WangEditor v-model:value="model.noticeContent!" />
|
||||||
</NFormItem>
|
</NFormItem>
|
||||||
</NForm>
|
</NForm>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
|
|||||||
Reference in New Issue
Block a user