修复重大故障: JwtAuthenticationFilter文件,远程读取用户接口导致的服务器请求数量跑满
This commit is contained in:
@@ -4,7 +4,6 @@ import type {CmsLink} from "~/api/cms/cmsLink/model";
|
||||
|
||||
const list = ref<CmsLink[]>([])
|
||||
listCmsLink({}).then(res => {
|
||||
console.log(res);
|
||||
list.value = res;
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import {useConfigInfo} from "~/composables/configState";
|
||||
import {useConfigInfo, useSetting} from "~/composables/configState";
|
||||
const config = useConfigInfo();
|
||||
const setting = useSetting()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div id="toolbar" v-if="config">
|
||||
<div id="toolbar" v-if="setting.floatTool">
|
||||
<ul>
|
||||
<li><a :href="`http://wpa.qq.com/msgrd?v=3&uin=${config.qqCode}&site=qq&menu=yes`" target="_blank">
|
||||
<span class="icon-font icon-qq"></span>
|
||||
@@ -22,9 +23,9 @@ const config = useConfigInfo();
|
||||
<span class="icon-font icon-message"></span>
|
||||
<span class="wz">在线留言</span>
|
||||
</a></li>
|
||||
<el-backtop :bottom="50" :right="25"><li class="backtop"><span class="icon-font icon-top"></span></li></el-backtop>
|
||||
</ul>
|
||||
</div>
|
||||
<el-backtop :bottom="50" :right="25"></el-backtop>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@@ -1,53 +1,57 @@
|
||||
<template>
|
||||
<div class="fr clearfix flex items-center">
|
||||
<div class="fl mr-5">
|
||||
<div v-if="setting.searchBtn" class="fl mr-5">
|
||||
<el-input v-model="keywords" :placeholder="`${$t('searchKeywords')}`" :suffix-icon="Search" @change="onSearch"/>
|
||||
</div>
|
||||
<!-- 未登录 -->
|
||||
<div v-if="!token" class="lang flex justify-center text-center items-center">
|
||||
<el-space>
|
||||
<nuxt-link to="/passport/login?type=register" type="text" class="text-sm text-gray-500">注册</nuxt-link>
|
||||
<el-divider direction="vertical"/>
|
||||
<nuxt-link to="/passport/login" type="text" class="text-sm text-gray-500">登录</nuxt-link>
|
||||
</el-space>
|
||||
</div>
|
||||
<!-- 已登录 -->
|
||||
<div v-else>
|
||||
<div class="header__right items-center pr-4 xl:pr-0 md:flex hidden">
|
||||
<el-space class="sm:flex hidden" size="large">
|
||||
<ClientOnly>
|
||||
<template v-if="token">
|
||||
<el-dropdown @command="handleCommand">
|
||||
<el-space class="flex items-center cursor-pointer">
|
||||
<el-avatar class="cursor-pointer" :src="user?.avatar" :size="30" />
|
||||
<span>{{ user?.nickname }}</span>
|
||||
</el-space>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item command="user"><nuxt-link to="/user">用户中心</nuxt-link></el-dropdown-item>
|
||||
<el-dropdown-item command="password"><nuxt-link to="/user/password">修改密码</nuxt-link></el-dropdown-item>
|
||||
<el-dropdown-item command="auth"><nuxt-link to="/user/auth">实名认证</nuxt-link></el-dropdown-item>
|
||||
<el-dropdown-item divided command="order"><nuxt-link to="/user/order">我的订单</nuxt-link></el-dropdown-item>
|
||||
<el-dropdown-item divided command="logOut"><nuxt-link to="/user/logout">退出登录</nuxt-link>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-button type="primary" v-if="!token" @click="navigateTo(`/passport/login`)">登录/注册</el-button>
|
||||
<!-- <el-button v-if="config.showLoginButton" circle :icon="ElIconUserFilled" @click="goLogin"></el-button>-->
|
||||
</template>
|
||||
</ClientOnly>
|
||||
<template v-if="setting.loginBtn">
|
||||
<!-- 未登录 -->
|
||||
<div v-if="!token" class="lang flex justify-center text-center items-center">
|
||||
<el-space>
|
||||
<nuxt-link to="/passport/login?type=register" type="text" class="text-sm text-gray-500">注册</nuxt-link>
|
||||
<el-divider direction="vertical"/>
|
||||
<nuxt-link to="/passport/login" type="text" class="text-sm text-gray-500">登录</nuxt-link>
|
||||
</el-space>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 已登录 -->
|
||||
<div v-else>
|
||||
<div class="header__right items-center pr-4 xl:pr-0 md:flex hidden">
|
||||
<el-space class="sm:flex hidden" size="large">
|
||||
<ClientOnly>
|
||||
<template v-if="token">
|
||||
<el-dropdown @command="handleCommand">
|
||||
<el-space class="flex items-center cursor-pointer">
|
||||
<el-avatar class="cursor-pointer" :src="user?.avatar" :size="30" />
|
||||
<span>{{ user?.nickname }}</span>
|
||||
</el-space>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item command="user"><nuxt-link to="/user">用户中心</nuxt-link></el-dropdown-item>
|
||||
<el-dropdown-item command="password"><nuxt-link to="/user/password">修改密码</nuxt-link></el-dropdown-item>
|
||||
<el-dropdown-item command="auth"><nuxt-link to="/user/auth">实名认证</nuxt-link></el-dropdown-item>
|
||||
<el-dropdown-item divided command="order"><nuxt-link to="/user/order">已购插件</nuxt-link></el-dropdown-item>
|
||||
<el-dropdown-item divided command="logOut"><nuxt-link to="/user/logout">退出登录</nuxt-link>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-button type="primary" v-if="!token" @click="navigateTo(`/passport/login`)">登录/注册</el-button>
|
||||
<!-- <el-button v-if="config.showLoginButton" circle :icon="ElIconUserFilled" @click="goLogin"></el-button>-->
|
||||
</template>
|
||||
</ClientOnly>
|
||||
</el-space>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { Search } from '@element-plus/icons-vue'
|
||||
import {useConfigInfo, useSetting} from "~/composables/configState";
|
||||
const token = useToken();
|
||||
const user = useUser();
|
||||
const setting = useSetting();
|
||||
const keywords = ref<string>();
|
||||
|
||||
const onSearch = () => {
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
<template>
|
||||
<nuxt-link to="/" class="flex items-center cursor-pointer gap-sm mr-7" v-if="logo">
|
||||
<!-- <el-image src="https://oss.wsdns.cn/20250211/eedb87d7b95b41e3bc9eca1247c85fa4.png" class="h-[30px]" size="small" shape="square" />-->
|
||||
<!-- <h4 class="text-gray-700 text-xl font-bold">WEBSOFT</h4>-->
|
||||
<el-image :src="logo?.value" class=" rounded-sm rounded-sm w-[107px] h-[24px]"/>
|
||||
<!-- <div class="text-sm text-gray-700 text-xl font-bold" :style="`${logo?.style}`">{{ website?.websiteName }}</div>-->
|
||||
<nuxt-link to="/" class="flex items-center cursor-pointer gap-sm mr-7" v-if="website">
|
||||
<el-image v-if="website.websiteLogo || logo?.value" :style="`${logo?.style}`" :src="logo?.value || website?.websiteLogo" class=" rounded-sm rounded-sm w-[107px] h-[24px]"/>
|
||||
<h4 v-else class="text-gray-700 text-xl font-bold" :style="`${logo?.style}`">{{ website?.websiteName }}</h4>
|
||||
</nuxt-link>
|
||||
</template>
|
||||
|
||||
@@ -11,7 +9,6 @@
|
||||
import {useLogo, useWebsite} from "~/composables/configState";
|
||||
import {listCmsWebsiteField} from "~/api/cms/cmsWebsiteField";
|
||||
const logo = useLogo()
|
||||
const config = useAppConfig();
|
||||
const website = useWebsite();
|
||||
|
||||
listCmsWebsiteField({
|
||||
|
||||
@@ -1,18 +1,24 @@
|
||||
<template>
|
||||
<MdPreview v-if="editor === 2" :id="id" :modelValue="data" />
|
||||
<div v-else v-html="data"></div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { MdPreview } from 'md-editor-v3';
|
||||
import 'md-editor-v3/lib/preview.css';
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
data?: any;
|
||||
isMobile?: boolean;
|
||||
}>(),
|
||||
{}
|
||||
defineProps<{
|
||||
data?: any;
|
||||
editor?: number;
|
||||
isMobile?: boolean;
|
||||
}>(),
|
||||
{}
|
||||
);
|
||||
|
||||
const id = 'preview-only';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-html="data"></div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.content {
|
||||
overflow: hidden;
|
||||
|
||||
@@ -1,242 +0,0 @@
|
||||
<!-- 富文本编辑器 -->
|
||||
<template>
|
||||
<component v-if="inlineEditor" :is="tagName" :id="elementId" />
|
||||
<textarea v-else :id="elementId"></textarea>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
watch,
|
||||
onMounted,
|
||||
onBeforeUnmount,
|
||||
onActivated,
|
||||
onDeactivated,
|
||||
nextTick,
|
||||
useAttrs
|
||||
} from 'vue';
|
||||
import tinymce from 'tinymce/tinymce';
|
||||
import type {
|
||||
Editor as TinyMCEEditor,
|
||||
EditorEvent,
|
||||
RawEditorSettings
|
||||
} from 'tinymce';
|
||||
import 'tinymce/themes/silver';
|
||||
import 'tinymce/icons/default';
|
||||
import 'tinymce/plugins/code';
|
||||
import 'tinymce/plugins/preview';
|
||||
import 'tinymce/plugins/fullscreen';
|
||||
import 'tinymce/plugins/paste';
|
||||
import 'tinymce/plugins/searchreplace';
|
||||
import 'tinymce/plugins/save';
|
||||
import 'tinymce/plugins/autosave';
|
||||
import 'tinymce/plugins/link';
|
||||
import 'tinymce/plugins/autolink';
|
||||
import 'tinymce/plugins/image';
|
||||
import 'tinymce/plugins/media';
|
||||
import 'tinymce/plugins/table';
|
||||
import 'tinymce/plugins/codesample';
|
||||
import 'tinymce/plugins/lists';
|
||||
import 'tinymce/plugins/advlist';
|
||||
import 'tinymce/plugins/hr';
|
||||
import 'tinymce/plugins/charmap';
|
||||
import 'tinymce/plugins/emoticons';
|
||||
import 'tinymce/plugins/anchor';
|
||||
import 'tinymce/plugins/directionality';
|
||||
import 'tinymce/plugins/pagebreak';
|
||||
import 'tinymce/plugins/quickbars';
|
||||
import 'tinymce/plugins/nonbreaking';
|
||||
import 'tinymce/plugins/visualblocks';
|
||||
import 'tinymce/plugins/visualchars';
|
||||
import 'tinymce/plugins/wordcount';
|
||||
import 'tinymce/plugins/emoticons/js/emojis';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useThemeStore } from '@/store/modules/theme';
|
||||
import {
|
||||
DEFAULT_CONFIG,
|
||||
DARK_CONFIG,
|
||||
uuid,
|
||||
bindHandlers,
|
||||
openAlert
|
||||
} from './util';
|
||||
import type { AlertOption } from './util';
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
// 编辑器唯一 id
|
||||
id?: string;
|
||||
// v-model
|
||||
value?: string;
|
||||
// 编辑器配置
|
||||
init?: RawEditorSettings;
|
||||
// 是否内联模式
|
||||
inline?: boolean;
|
||||
// model events
|
||||
modelEvents?: string;
|
||||
// 内联模式标签名
|
||||
tagName?: string;
|
||||
// 是否禁用
|
||||
disabled?: boolean;
|
||||
// 是否跟随框架主题
|
||||
autoTheme?: boolean;
|
||||
// 不跟随框架主题时是否使用暗黑主题
|
||||
darkTheme?: boolean;
|
||||
}>(),
|
||||
{
|
||||
inline: false,
|
||||
modelEvents: 'change input undo redo',
|
||||
tagName: 'div',
|
||||
autoTheme: true
|
||||
}
|
||||
);
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:value', value: string): void;
|
||||
}>();
|
||||
|
||||
const attrs = useAttrs();
|
||||
const themeStore = useThemeStore();
|
||||
const { darkMode } = storeToRefs(themeStore);
|
||||
|
||||
// 编辑器唯一 id
|
||||
const elementId: string = props.id || uuid('tiny-vue');
|
||||
|
||||
// 编辑器实例
|
||||
let editorIns: TinyMCEEditor | null = null;
|
||||
|
||||
// 是否内联模式
|
||||
const inlineEditor: boolean = props.init?.inline || props.inline;
|
||||
|
||||
/* 更新 value */
|
||||
const updateValue = (value: string) => {
|
||||
emit('update:value', value);
|
||||
};
|
||||
|
||||
/* 修改内容 */
|
||||
const setContent = (value?: string) => {
|
||||
if (
|
||||
editorIns &&
|
||||
typeof value === 'string' &&
|
||||
value !== editorIns.getContent()
|
||||
) {
|
||||
editorIns.setContent(value);
|
||||
}
|
||||
};
|
||||
|
||||
/* 渲染编辑器 */
|
||||
const render = () => {
|
||||
const isDark = props.autoTheme ? darkMode.value : props.darkTheme;
|
||||
tinymce.init({
|
||||
...DEFAULT_CONFIG,
|
||||
...(isDark ? DARK_CONFIG : {}),
|
||||
...props.init,
|
||||
selector: `#${elementId}`,
|
||||
readonly: props.disabled,
|
||||
inline: inlineEditor,
|
||||
setup: (editor: TinyMCEEditor) => {
|
||||
editorIns = editor;
|
||||
editor.on('init', (e: EditorEvent<any>) => {
|
||||
// 回显初始值
|
||||
if (props.value) {
|
||||
setContent(props.value);
|
||||
}
|
||||
// v-model
|
||||
editor.on(props.modelEvents, () => {
|
||||
updateValue(editor.getContent());
|
||||
});
|
||||
// valid events
|
||||
bindHandlers(e, attrs, editor);
|
||||
});
|
||||
if (typeof props.init?.setup === 'function') {
|
||||
props.init.setup(editor);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/* 销毁编辑器 */
|
||||
const destory = () => {
|
||||
if (tinymce != null && editorIns != null) {
|
||||
tinymce.remove(editorIns as any);
|
||||
editorIns = null;
|
||||
}
|
||||
};
|
||||
|
||||
/* 弹出提示框 */
|
||||
const alert = (option?: AlertOption) => {
|
||||
openAlert(editorIns, option);
|
||||
};
|
||||
|
||||
defineExpose({ editorIns, alert });
|
||||
|
||||
watch(
|
||||
() => props.value,
|
||||
(val: string, prevVal: string) => {
|
||||
if (val !== prevVal) {
|
||||
setContent(val);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.disabled,
|
||||
(disable) => {
|
||||
if (editorIns !== null) {
|
||||
if (typeof editorIns.mode?.set === 'function') {
|
||||
editorIns.mode.set(disable ? 'readonly' : 'design');
|
||||
} else {
|
||||
editorIns.setMode(disable ? 'readonly' : 'design');
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.tagName,
|
||||
() => {
|
||||
destory();
|
||||
nextTick(() => {
|
||||
render();
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
watch(darkMode, () => {
|
||||
if (props.autoTheme) {
|
||||
destory();
|
||||
nextTick(() => {
|
||||
render();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
render();
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
destory();
|
||||
});
|
||||
|
||||
onActivated(() => {
|
||||
render();
|
||||
});
|
||||
|
||||
onDeactivated(() => {
|
||||
destory();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
body .tox-tinymce-aux {
|
||||
z-index: 19990000;
|
||||
}
|
||||
|
||||
textarea[id^='tiny-vue'] {
|
||||
width: 0;
|
||||
height: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
opacity: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
</style>
|
||||
@@ -1,248 +0,0 @@
|
||||
import type {
|
||||
Editor as TinyMCEEditor,
|
||||
EditorEvent,
|
||||
RawEditorSettings
|
||||
} from 'tinymce';
|
||||
const BASE_URL = import.meta.env.BASE_URL;
|
||||
|
||||
// 默认加载插件
|
||||
const PLUGINS: string = [
|
||||
'code',
|
||||
'preview',
|
||||
'fullscreen',
|
||||
'paste',
|
||||
'searchreplace',
|
||||
'save',
|
||||
'autosave',
|
||||
'link',
|
||||
'autolink',
|
||||
'image',
|
||||
'media',
|
||||
'table',
|
||||
'codesample',
|
||||
'lists',
|
||||
'advlist',
|
||||
'hr',
|
||||
'charmap',
|
||||
'emoticons',
|
||||
'anchor',
|
||||
'directionality',
|
||||
'pagebreak',
|
||||
'quickbars',
|
||||
'nonbreaking',
|
||||
'visualblocks',
|
||||
'visualchars',
|
||||
'wordcount'
|
||||
].join(' ');
|
||||
|
||||
// 默认工具栏布局
|
||||
const TOOLBAR: string = [
|
||||
'fullscreen',
|
||||
'preview',
|
||||
'code',
|
||||
'codesample',
|
||||
'emoticons',
|
||||
'image',
|
||||
'media',
|
||||
'|',
|
||||
'undo',
|
||||
'redo',
|
||||
'|',
|
||||
'forecolor',
|
||||
'backcolor',
|
||||
'|',
|
||||
'bold',
|
||||
'italic',
|
||||
'underline',
|
||||
'strikethrough',
|
||||
'|',
|
||||
'alignleft',
|
||||
'aligncenter',
|
||||
'alignright',
|
||||
'alignjustify',
|
||||
'|',
|
||||
'outdent',
|
||||
'indent',
|
||||
'|',
|
||||
'numlist',
|
||||
'bullist',
|
||||
'|',
|
||||
'formatselect',
|
||||
'fontselect',
|
||||
'fontsizeselect',
|
||||
'|',
|
||||
'link',
|
||||
'charmap',
|
||||
'anchor',
|
||||
'pagebreak',
|
||||
'|',
|
||||
'ltr',
|
||||
'rtl'
|
||||
].join(' ');
|
||||
|
||||
// 默认配置
|
||||
export const DEFAULT_CONFIG: RawEditorSettings = {
|
||||
height: 300,
|
||||
branding: false,
|
||||
skin_url: BASE_URL + 'tinymce/skins/ui/oxide',
|
||||
content_css: BASE_URL + 'tinymce/skins/content/default/content.min.css',
|
||||
language_url: BASE_URL + 'tinymce/langs/zh_CN.js',
|
||||
language: 'zh_CN',
|
||||
plugins: PLUGINS,
|
||||
toolbar: TOOLBAR,
|
||||
draggable_modal: true,
|
||||
toolbar_mode: 'sliding',
|
||||
quickbars_insert_toolbar: '',
|
||||
images_upload_handler: (blobInfo: any, success: any, error: any) => {
|
||||
if (blobInfo.blob().size / 1024 > 400) {
|
||||
error('大小不能超过 400KB');
|
||||
return;
|
||||
}
|
||||
success('data:image/jpeg;base64,' + blobInfo.base64());
|
||||
},
|
||||
file_picker_types: 'media',
|
||||
file_picker_callback: () => {}
|
||||
};
|
||||
|
||||
// 暗黑主题配置
|
||||
export const DARK_CONFIG: RawEditorSettings = {
|
||||
skin_url: BASE_URL + 'tinymce/skins/ui/oxide-dark',
|
||||
content_css: BASE_URL + 'tinymce/skins/content/dark/content.min.css'
|
||||
};
|
||||
|
||||
// 支持监听的事件
|
||||
export const VALID_EVENTS = [
|
||||
'onActivate',
|
||||
'onAddUndo',
|
||||
'onBeforeAddUndo',
|
||||
'onBeforeExecCommand',
|
||||
'onBeforeGetContent',
|
||||
'onBeforeRenderUI',
|
||||
'onBeforeSetContent',
|
||||
'onBeforePaste',
|
||||
'onBlur',
|
||||
'onChange',
|
||||
'onClearUndos',
|
||||
'onClick',
|
||||
'onContextMenu',
|
||||
'onCopy',
|
||||
'onCut',
|
||||
'onDblclick',
|
||||
'onDeactivate',
|
||||
'onDirty',
|
||||
'onDrag',
|
||||
'onDragDrop',
|
||||
'onDragEnd',
|
||||
'onDragGesture',
|
||||
'onDragOver',
|
||||
'onDrop',
|
||||
'onExecCommand',
|
||||
'onFocus',
|
||||
'onFocusIn',
|
||||
'onFocusOut',
|
||||
'onGetContent',
|
||||
'onHide',
|
||||
'onInit',
|
||||
'onKeyDown',
|
||||
'onKeyPress',
|
||||
'onKeyUp',
|
||||
'onLoadContent',
|
||||
'onMouseDown',
|
||||
'onMouseEnter',
|
||||
'onMouseLeave',
|
||||
'onMouseMove',
|
||||
'onMouseOut',
|
||||
'onMouseOver',
|
||||
'onMouseUp',
|
||||
'onNodeChange',
|
||||
'onObjectResizeStart',
|
||||
'onObjectResized',
|
||||
'onObjectSelected',
|
||||
'onPaste',
|
||||
'onPostProcess',
|
||||
'onPostRender',
|
||||
'onPreProcess',
|
||||
'onProgressState',
|
||||
'onRedo',
|
||||
'onRemove',
|
||||
'onReset',
|
||||
'onSaveContent',
|
||||
'onSelectionChange',
|
||||
'onSetAttrib',
|
||||
'onSetContent',
|
||||
'onShow',
|
||||
'onSubmit',
|
||||
'onUndo',
|
||||
'onVisualAid'
|
||||
];
|
||||
|
||||
let unique = 0;
|
||||
|
||||
/**
|
||||
* 生成编辑器 id
|
||||
*/
|
||||
export function uuid(prefix: string): string {
|
||||
const time = Date.now();
|
||||
const random = Math.floor(Math.random() * 1000000000);
|
||||
unique++;
|
||||
return prefix + '_' + random + unique + String(time);
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定事件
|
||||
*/
|
||||
export function bindHandlers(
|
||||
initEvent: EditorEvent<any>,
|
||||
listeners: Record<string, any>,
|
||||
editor: TinyMCEEditor
|
||||
): void {
|
||||
const validEvents = VALID_EVENTS.map((event) => event.toLowerCase());
|
||||
Object.keys(listeners)
|
||||
.filter((key: string) => validEvents.includes(key.toLowerCase()))
|
||||
.forEach((key: string) => {
|
||||
const handler = listeners[key];
|
||||
if (typeof handler === 'function') {
|
||||
if (key === 'onInit') {
|
||||
handler(initEvent, editor);
|
||||
} else {
|
||||
editor.on(key.substring(2), (e: EditorEvent<any>) =>
|
||||
handler(e, editor)
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 弹出提示框
|
||||
*/
|
||||
export function openAlert(
|
||||
editor: TinyMCEEditor | null,
|
||||
option: AlertOption = {}
|
||||
) {
|
||||
editor?.windowManager?.open({
|
||||
title: option.title ?? '提示',
|
||||
body: {
|
||||
type: 'panel',
|
||||
items: [
|
||||
{
|
||||
type: 'htmlpanel',
|
||||
html: `<p>${option.content ?? ''}</p>`
|
||||
}
|
||||
]
|
||||
},
|
||||
buttons: [
|
||||
{
|
||||
type: 'cancel',
|
||||
name: 'closeButton',
|
||||
text: '确定',
|
||||
primary: true
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
export interface AlertOption {
|
||||
title?: string;
|
||||
content?: string;
|
||||
}
|
||||
Reference in New Issue
Block a user