| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286 |
- /**
- * Copyright (c) 2013-Now https://jeesite.com All rights reserved.
- * No deletion without permission, or be held responsible to law.
- * @author Vben、ThinkGem
- */
- import type { ModalFunc, ModalFuncProps } from 'ant-design-vue/lib/modal/Modal';
- import { Modal, message as Message, notification } from 'ant-design-vue';
- import { InfoCircleFilled, CheckCircleFilled, CloseCircleFilled } from '@ant-design/icons-vue';
- import { NotificationArgsProps, ConfigProps } from 'ant-design-vue/lib/notification';
- import { useI18n } from './useI18n';
- import { isString } from '@jeesite/core/utils/is';
- import { Icon } from '@jeesite/core/components/Icon';
- import type { ConfigOnClose, MessageType } from 'ant-design-vue/lib/message';
- import type { JointContent } from 'ant-design-vue/es/message/interface';
- export interface NotifyApi {
- info(config: NotificationArgsProps): void;
- success(config: NotificationArgsProps): void;
- error(config: NotificationArgsProps): void;
- warn(config: NotificationArgsProps): void;
- warning(config: NotificationArgsProps): void;
- open(args: NotificationArgsProps): void;
- close(key: string): void;
- config(options: ConfigProps): void;
- destroy(): void;
- }
- export declare type NotificationPlacement = 'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight';
- export declare type IconType = 'success' | 'info' | 'error' | 'warning';
- export interface ModalOptionsEx extends Omit<ModalFuncProps, 'iconType'> {
- iconType: 'warning' | 'success' | 'error' | 'info';
- icon?: any;
- title?: any;
- content?: any;
- }
- export type ModalOptionsPartial = Partial<ModalOptionsEx> & Pick<ModalOptionsEx, 'content'>;
- interface ConfirmOptions {
- info: ModalFunc;
- success: ModalFunc;
- error: ModalFunc;
- warn: ModalFunc;
- warning: ModalFunc;
- }
- function getIcon(iconType: string) {
- if (iconType === 'warning') {
- return <InfoCircleFilled class="modal-icon-warning" />;
- } else if (iconType === 'success') {
- return <CheckCircleFilled class="modal-icon-success" />;
- } else if (iconType === 'info') {
- return <InfoCircleFilled class="modal-icon-info" />;
- } else {
- return <CloseCircleFilled class="modal-icon-error" />;
- }
- }
- function renderContent({ content }: Pick<ModalOptionsEx, 'content'>) {
- if (isString(content)) {
- return <div innerHTML={`<div>${content as string}</div>`}></div>;
- } else {
- return content;
- }
- }
- /**
- * @description: Create confirmation box
- */
- function createConfirm(options: ModalOptionsEx) {
- const iconType = options.iconType || 'info';
- Reflect.deleteProperty(options, 'iconType');
- const opt: ModalFuncProps = {
- centered: true,
- icon: getIcon(iconType),
- ...options,
- content: renderContent(options),
- maskClosable: false,
- };
- return Modal.confirm(opt);
- }
- const getBaseOptions = () => {
- const { t } = useI18n();
- return {
- okText: t('common.okText'),
- centered: true,
- };
- };
- function createModalOptions(options: ModalOptionsPartial, icon: string): ModalOptionsPartial | any {
- return {
- ...getBaseOptions(),
- ...options,
- content: renderContent(options),
- icon: getIcon(icon),
- maskClosable: false,
- };
- }
- function createSuccessModal(options: ModalOptionsPartial) {
- return Modal.success(createModalOptions(options, 'success'));
- }
- function createErrorModal(options: ModalOptionsPartial) {
- return Modal.error(createModalOptions(options, 'close'));
- }
- function createInfoModal(options: ModalOptionsPartial) {
- return Modal.info(createModalOptions(options, 'info'));
- }
- function createWarningModal(options: ModalOptionsPartial) {
- return Modal.warning(createModalOptions(options, 'warning'));
- }
- function contains(str, searchs) {
- if (typeof str === 'object' && str.content) {
- str = str.content;
- }
- if (typeof str === 'object' && str.props?.innerHTML) {
- str = str.props?.innerHTML;
- }
- if (typeof str === 'string' && searchs) {
- const ss = searchs.split(',');
- for (let i = 0; i < ss.length; i++) {
- if (str.indexOf(ss[i]) >= 0) {
- return true;
- }
- }
- }
- return false;
- }
- const MESSAGE_DEDUPE_INTERVAL = 1200;
- const GENERIC_SUCCESS_MESSAGE_KEY = '__jeesite_generic_success_message__';
- const recentMessageMap = new Map<string, number>();
- function getContentText(content: any): string {
- if (typeof content === 'string') return content;
- if (typeof content === 'number') return String(content);
- if (content?.content) return getContentText(content.content);
- if (content?.props?.innerHTML) return String(content.props.innerHTML);
- return '';
- }
- function normalizeMessageText(content: any) {
- return getContentText(content).trim();
- }
- function isGenericSuccessMessage(content: any) {
- return normalizeMessageText(content).replace(/[!!。.\s]/g, '') === '操作成功';
- }
- function shouldSkipDuplicateMessage(type: string, content: any) {
- const text = normalizeMessageText(content);
- if (!text) return false;
- const key = `${type}:${text}`;
- const now = Date.now();
- const lastTime = recentMessageMap.get(key) || 0;
- recentMessageMap.set(key, now);
- return now - lastTime < MESSAGE_DEDUPE_INTERVAL;
- }
- function buildGenericSuccessConfig(content: JointContent, duration?: number, onClose?: ConfigOnClose) {
- if (typeof content === 'object' && content && 'content' in content) {
- return {
- ...content,
- key: (content as any).key || GENERIC_SUCCESS_MESSAGE_KEY,
- duration: (content as any).duration ?? duration,
- onClose: (content as any).onClose ?? onClose,
- };
- }
- return {
- content,
- key: GENERIC_SUCCESS_MESSAGE_KEY,
- duration,
- onClose,
- };
- }
- function showDedupeMessage(type: string, content: JointContent, duration?: number, onClose?: ConfigOnClose) {
- if (shouldSkipDuplicateMessage(type, content)) {
- return () => {};
- }
- if (type === 'success') {
- if (isGenericSuccessMessage(content)) {
- return Message.success(buildGenericSuccessConfig(content, duration, onClose));
- }
- Message.destroy(GENERIC_SUCCESS_MESSAGE_KEY);
- }
- if (type === 'error') {
- return Message.error(content, duration, onClose);
- } else if (type === 'warning') {
- return Message.warning(content, duration, onClose);
- } else if (type === 'success') {
- return Message.success(content, duration, onClose);
- } else {
- return Message.info(content, duration, onClose);
- }
- }
- function createDedupeMessageApi() {
- return new Proxy(Message as any, {
- get(target: any, prop: string | symbol) {
- if (typeof prop === 'string' && ['success', 'error', 'warning', 'warn', 'info'].includes(prop)) {
- const type = prop === 'warn' ? 'warning' : prop;
- return (content: JointContent, duration?: number, onClose?: ConfigOnClose) =>
- showDedupeMessage(type, content, duration, onClose);
- }
- return target[prop];
- },
- }) as typeof Message;
- }
- function showMessageModal(options: ModalOptionsPartial | string, type?: string) {
- const { t } = useI18n();
- if (typeof options === 'string') options = { content: options };
- if (typeof options.content === 'string' && options.content.startsWith('posfull:')) {
- options.content = '<div class="modal-posfull-content">' + options.content.substring(8) + '</div>';
- options.width = '80%';
- }
- if (type === 'error' || contains(options.content, t('sys.message.error'))) {
- return Modal.error(createModalOptions(options, 'close'));
- } else if (type === 'warning' || contains(options.content, t('sys.message.warning'))) {
- return Modal.warning(createModalOptions(options, 'warning'));
- } else if (type === 'success' || contains(options.content, t('sys.message.success'))) {
- return Modal.success(createModalOptions(options, 'success'));
- } else {
- return Modal.info(createModalOptions(options, 'info'));
- }
- }
- function showMessage(content: JointContent, type?: string, duration?: number, onClose?: ConfigOnClose) {
- const { t } = useI18n();
- let messageRemove = () => {};
- if (typeof content === 'string' && content.startsWith('posfull:')) {
- content = {
- content: (
- <div style="position: relative;" onMouseout={() => setTimeout(messageRemove, 1000)}>
- <div style="position: absolute; right: -6px; top: -20px;" onClick={() => messageRemove()}>
- <Icon icon="i-ant-design:close-outlined" color="#555" class="cursor-pointer" />
- </div>
- <div class="text-left" innerHTML={content.substring(8)}></div>
- </div>
- ),
- duration,
- };
- }
- if (type === 'error' || contains(content, t('sys.message.error'))) {
- messageRemove = showDedupeMessage('error', content, duration, onClose);
- } else if (type === 'warning' || contains(content, t('sys.message.warning'))) {
- messageRemove = showDedupeMessage('warning', content, duration, onClose);
- } else if (type === 'success' || contains(content, t('sys.message.success')) || isGenericSuccessMessage(content)) {
- messageRemove = showDedupeMessage('success', content, duration, onClose);
- } else {
- messageRemove = showDedupeMessage('info', content, duration, onClose);
- }
- return messageRemove;
- }
- notification.config({
- placement: 'topRight',
- duration: 3,
- });
- /**
- * @description: message
- */
- export function useMessage() {
- return {
- createMessage: createDedupeMessageApi(),
- notification: notification as NotifyApi,
- createConfirm: createConfirm,
- createSuccessModal,
- createErrorModal,
- createInfoModal,
- createWarningModal,
- showMessageModal,
- showMessage,
- };
- }
|