From 33bd64d9ff35bc4141c88361601f37e6de125014 Mon Sep 17 00:00:00 2001
From: xiaoxian521 <1923740402@qq.com>
Date: Sun, 27 Nov 2022 16:14:55 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=20`message`=20?=
=?UTF-8?q?=E6=B6=88=E6=81=AF=E6=8F=90=E7=A4=BA=E5=87=BD=E6=95=B0=EF=BC=8C?=
=?UTF-8?q?=E5=85=BC=E5=AE=B9=20`Element=20Plus`=20=E5=92=8C=20`Ant=20Desi?=
=?UTF-8?q?gn`=20=E4=B8=A4=E7=A7=8D=20`Message`=20=E9=A3=8E=E6=A0=BC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
locales/en.yaml | 1 +
locales/zh-CN.yaml | 1 +
src/router/modules/components.ts | 18 +-
src/style/dark.scss | 14 ++
src/style/element-plus.scss | 27 +++
src/utils/message.ts | 88 ++++++--
src/views/components/message/index.vue | 196 ++++++++++++++++++
src/views/login/components/phone.vue | 2 +-
src/views/login/components/regist.vue | 6 +-
src/views/login/components/update.vue | 4 +-
src/views/login/index.vue | 2 +-
.../base/column-template/columns.tsx | 9 +-
.../base/header-renderer/columns.tsx | 9 +-
src/views/pure-table/high.vue | 11 +
.../pure-table/high/contextmenu/columns.tsx | 4 +-
src/views/pure-table/high/echarts/columns.tsx | 4 +-
src/views/pure-table/high/edit/columns.tsx | 4 +-
src/views/pure-table/high/execl/columns.tsx | 4 +-
src/views/pure-table/index.vue | 11 +
src/views/system/role/columns.tsx | 4 +-
src/views/system/user/columns.tsx | 4 +-
tsconfig.json | 3 +-
22 files changed, 381 insertions(+), 45 deletions(-)
create mode 100644 src/views/components/message/index.vue
diff --git a/locales/en.yaml b/locales/en.yaml
index 89c6a7140..5c965520e 100644
--- a/locales/en.yaml
+++ b/locales/en.yaml
@@ -37,6 +37,7 @@ menus:
hsfourZeroOne: "403"
hsFive: "500"
hscomponents: Components
+ hsmessage: Message Tips Components
hsvideo: Video Components
hsmap: Map Components
hsdraggable: Draggable Components
diff --git a/locales/zh-CN.yaml b/locales/zh-CN.yaml
index f7c370468..5db781115 100644
--- a/locales/zh-CN.yaml
+++ b/locales/zh-CN.yaml
@@ -37,6 +37,7 @@ menus:
hsfourZeroOne: "403"
hsFive: "500"
hscomponents: 组件
+ hsmessage: 消息提示组件
hsvideo: 视频组件
hsmap: 地图组件
hsdraggable: 拖拽组件
diff --git a/src/router/modules/components.ts b/src/router/modules/components.ts
index 26feab9c0..43b880c7c 100644
--- a/src/router/modules/components.ts
+++ b/src/router/modules/components.ts
@@ -10,6 +10,18 @@ export default {
rank: components
},
children: [
+ {
+ path: "/components/message",
+ name: "Message",
+ component: () => import("@/views/components/message/index.vue"),
+ meta: {
+ title: $t("menus.hsmessage"),
+ extraIcon: {
+ svg: true,
+ name: "team-iconxinpinrenqiwang"
+ }
+ }
+ },
{
path: "/components/video",
name: "Video",
@@ -47,11 +59,7 @@ export default {
name: "SplitPane",
component: () => import("@/views/components/split-pane/index.vue"),
meta: {
- title: $t("menus.hssplitPane"),
- extraIcon: {
- svg: true,
- name: "team-iconxinpinrenqiwang"
- }
+ title: $t("menus.hssplitPane")
}
},
{
diff --git a/src/style/dark.scss b/src/style/dark.scss
index 23008ada6..348575631 100644
--- a/src/style/dark.scss
+++ b/src/style/dark.scss
@@ -186,4 +186,18 @@ html.dark {
.el-dropdown-menu__item:not(.is-disabled):hover {
background: transparent;
}
+
+ /* 克隆并自定义 ElMessage 样式,不会影响 ElMessage 原本样式,在 src/utils/message.ts 中调用自定义样式 ElMessage 方法即可,非暗黑模式在 src/style/element-plus.scss 文件进行了适配 */
+ .pure-message {
+ background-image: initial !important;
+ background-color: rgb(36, 37, 37) !important;
+ box-shadow: rgb(13 13 13 / 12%) 0px 3px 6px -4px,
+ rgb(13 13 13 / 8%) 0px 6px 16px 0px, rgb(13 13 13 / 5%) 0px 9px 28px 8px !important;
+
+ & .el-message__content {
+ color: $color-white !important;
+ pointer-events: all !important;
+ background-image: initial !important;
+ }
+ }
}
diff --git a/src/style/element-plus.scss b/src/style/element-plus.scss
index a24c30fb6..aa357b95c 100644
--- a/src/style/element-plus.scss
+++ b/src/style/element-plus.scss
@@ -62,3 +62,30 @@
border-left-color: var(--el-color-primary);
}
}
+
+/* 克隆并自定义 ElMessage 样式,不会影响 ElMessage 原本样式,在 src/utils/message.ts 中调用自定义样式 ElMessage 方法即可,暗黑模式在 src/style/dark.scss 文件进行了适配 */
+.pure-message {
+ border-width: 0 !important;
+ background: #fff !important;
+ padding: 10px 13px !important;
+ box-shadow: 0 3px 6px -4px #0000001f, 0 6px 16px #00000014,
+ 0 9px 28px 8px #0000000d !important;
+
+ &.el-message.is-closable .el-message__content {
+ padding-right: 17px !important;
+ }
+
+ & .el-message__content {
+ color: #000000d9 !important;
+ pointer-events: all !important;
+ background-image: initial !important;
+ }
+
+ & .el-message__icon {
+ margin-right: 8px !important;
+ }
+
+ & .el-message__closeBtn {
+ right: 9px !important;
+ }
+}
diff --git a/src/utils/message.ts b/src/utils/message.ts
index 86b631cbf..54b100f59 100644
--- a/src/utils/message.ts
+++ b/src/utils/message.ts
@@ -1,32 +1,84 @@
+import { type VNode } from "vue";
+import { isFunction } from "@pureadmin/utils";
import { type MessageHandler, ElMessage } from "element-plus";
-// 更多配置请看:https://element-plus.org/zh-CN/component/message.html#message-%E9%85%8D%E7%BD%AE%E9%A1%B9
+type messageStyle = "el" | "antd";
+type messageTypes = "info" | "success" | "warning" | "error";
-type messageTypes = "success" | "info" | "warning" | "error";
+interface MessageParams {
+ /** 消息类型,可选 `info` 、`success` 、`warning` 、`error` ,默认 `info` */
+ type?: messageTypes;
+ /** 自定义图标,该属性会覆盖 `type` 的图标 */
+ icon?: any;
+ /** 是否将 `message` 属性作为 `HTML` 片段处理,默认 `false` */
+ dangerouslyUseHTMLString?: boolean;
+ /** 消息风格,可选 `el` 、`antd` ,默认 `antd` */
+ customClass?: messageStyle;
+ /** 显示时间,单位为毫秒。设为 `0` 则不会自动关闭,`element-plus` 默认是 `3000` ,平台改成默认 `2000` */
+ duration?: number;
+ /** 是否显示关闭按钮,默认值 `false` */
+ showClose?: boolean;
+ /** 文字是否居中,默认值 `false` */
+ center?: boolean;
+ /** `Message` 距离窗口顶部的偏移量,默认 `20` */
+ offset?: number;
+ /** 设置组件的根元素,默认 `document.body` */
+ appendTo?: string | HTMLElement;
+ /** 合并内容相同的消息,不支持 `VNode` 类型的消息,默认值 `false` */
+ grouping?: boolean;
+ /** 关闭时的回调函数, 参数为被关闭的 `message` 实例 */
+ onClose?: Function | null;
+}
+
+/** 用法非常简单,参考 src/views/components/message/index.vue 文件 */
/**
- * `element-plus` 的 `info` 消息类型
+ * `Message` 消息提示函数
*/
const message = (
- message: string,
- type = "info" as messageTypes,
- showClose = true,
- duration = 2000,
- center = false,
- grouping = false
+ message: string | VNode | (() => VNode),
+ params?: MessageParams
): MessageHandler => {
- return ElMessage({
- message,
- type,
- showClose,
- duration,
- center,
- grouping
- });
+ if (!params) {
+ return ElMessage({
+ message,
+ customClass: "pure-message"
+ });
+ } else {
+ const {
+ icon,
+ type = "info",
+ dangerouslyUseHTMLString = false,
+ customClass = "antd",
+ duration = 2000,
+ showClose = false,
+ center = false,
+ offset = 20,
+ appendTo = document.body,
+ grouping = false,
+ onClose
+ } = params;
+
+ return ElMessage({
+ message,
+ type,
+ icon,
+ dangerouslyUseHTMLString,
+ duration,
+ showClose,
+ center,
+ offset,
+ appendTo,
+ grouping,
+ // 全局搜 pure-message 即可知道该类的样式位置
+ customClass: customClass === "antd" ? "pure-message" : "",
+ onClose: () => (isFunction(onClose) ? onClose() : null)
+ });
+ }
};
/**
- * 关闭 `element-plus` 的所有消息实例
+ * 关闭所有 `Message` 消息提示函数
*/
const closeAllMessage = (): void => ElMessage.closeAll();
diff --git a/src/views/components/message/index.vue b/src/views/components/message/index.vue
new file mode 100644
index 000000000..23c330d3a
--- /dev/null
+++ b/src/views/components/message/index.vue
@@ -0,0 +1,196 @@
+
+
+
+
+
+
+
+
+ element-plus 的消息提示,点击弹出提示信息
+
+
+
+ Info
+
+
+ Success
+
+
+ Warning
+
+
+ Error
+
+
+ 可关闭
+
+
+ 分组消息合并
+
+
+ 自定义图标
+
+
+ message('消息已关闭', { customClass: 'el', type: 'success' })
+ })
+ "
+ >
+ 自定义延时关闭时间并设置关闭后其他操作
+
+
+ 自定义内容
+
+ This is HTML string', {
+ customClass: 'el',
+ dangerouslyUseHTMLString: true
+ })
+ "
+ >
+ HTML 片段作为正文内容
+
+
+
+
+
+
+ 类似 Ant Design 风格的消息提示,点击弹出提示信息(基于 ElMessage
+ 样式改版,不会影响 ElMessage
+ 原本样式,使用和打包大小成本极低并适配暗黑模式)
+
+
+
+ Info
+
+ Success
+
+
+ Warning
+
+
+ Error
+
+
+ 可关闭
+
+
+ 分组消息合并
+
+
+ 自定义图标
+
+ message('消息已关闭', { type: 'success' })
+ })
+ "
+ >
+ 自定义延时关闭时间并设置关闭后其他操作
+
+
+ 自定义内容
+
+ This is HTML string', {
+ dangerouslyUseHTMLString: true
+ })
+ "
+ >
+ HTML 片段作为正文内容
+
+
+
+
+
+ 关闭所有消息提示
+
+
diff --git a/src/views/login/components/phone.vue b/src/views/login/components/phone.vue
index 583fe6e9b..4d547c625 100644
--- a/src/views/login/components/phone.vue
+++ b/src/views/login/components/phone.vue
@@ -26,7 +26,7 @@ const onLogin = async (formEl: FormInstance | undefined) => {
if (valid) {
// 模拟登录请求,需根据实际开发进行修改
setTimeout(() => {
- message(transformI18n($t("login.loginSuccess")), "success");
+ message(transformI18n($t("login.loginSuccess")), { type: "success" });
loading.value = false;
}, 2000);
} else {
diff --git a/src/views/login/components/regist.vue b/src/views/login/components/regist.vue
index 4110f4591..523889a6a 100644
--- a/src/views/login/components/regist.vue
+++ b/src/views/login/components/regist.vue
@@ -45,12 +45,14 @@ const onUpdate = async (formEl: FormInstance | undefined) => {
if (checked.value) {
// 模拟请求,需根据实际开发进行修改
setTimeout(() => {
- message(transformI18n($t("login.registerSuccess")), "success");
+ message(transformI18n($t("login.registerSuccess")), {
+ type: "success"
+ });
loading.value = false;
}, 2000);
} else {
loading.value = false;
- message(transformI18n($t("login.tickPrivacy")), "warning");
+ message(transformI18n($t("login.tickPrivacy")), { type: "warning" });
}
} else {
loading.value = false;
diff --git a/src/views/login/components/update.vue b/src/views/login/components/update.vue
index 984450111..3b973c091 100644
--- a/src/views/login/components/update.vue
+++ b/src/views/login/components/update.vue
@@ -42,7 +42,9 @@ const onUpdate = async (formEl: FormInstance | undefined) => {
if (valid) {
// 模拟请求,需根据实际开发进行修改
setTimeout(() => {
- message(transformI18n($t("login.passwordUpdateReg")), "success");
+ message(transformI18n($t("login.passwordUpdateReg")), {
+ type: "success"
+ });
loading.value = false;
}, 2000);
} else {
diff --git a/src/views/login/index.vue b/src/views/login/index.vue
index 122ab3328..fa76f5286 100644
--- a/src/views/login/index.vue
+++ b/src/views/login/index.vue
@@ -73,7 +73,7 @@ const onLogin = async (formEl: FormInstance | undefined) => {
// 获取后端路由
initRouter().then(() => {
router.push("/");
- message("登录成功", "success");
+ message("登录成功", { type: "success" });
});
}
});
diff --git a/src/views/pure-table/base/column-template/columns.tsx b/src/views/pure-table/base/column-template/columns.tsx
index 26066cb8b..0e6f53bd2 100644
--- a/src/views/pure-table/base/column-template/columns.tsx
+++ b/src/views/pure-table/base/column-template/columns.tsx
@@ -56,14 +56,13 @@ export function useColumns() {
];
const handleEdit = (index: number, row) => {
- message(
- `您编辑了第 ${index} 行,数据为:${JSON.stringify(row)}`,
- "success"
- );
+ message(`您编辑了第 ${index} 行,数据为:${JSON.stringify(row)}`, {
+ type: "success"
+ });
};
const handleDelete = (index: number, row) => {
- message(`您删除了第 ${index} 行,数据为:${JSON.stringify(row)}`, "info");
+ message(`您删除了第 ${index} 行,数据为:${JSON.stringify(row)}`);
};
return {
diff --git a/src/views/pure-table/base/header-renderer/columns.tsx b/src/views/pure-table/base/header-renderer/columns.tsx
index 08e4bbf71..d7871d55f 100644
--- a/src/views/pure-table/base/header-renderer/columns.tsx
+++ b/src/views/pure-table/base/header-renderer/columns.tsx
@@ -15,14 +15,13 @@ export function useColumns() {
);
const handleEdit = (index: number, row) => {
- message(
- `您编辑了第 ${index} 行,数据为:${JSON.stringify(row)}`,
- "success"
- );
+ message(`您编辑了第 ${index} 行,数据为:${JSON.stringify(row)}`, {
+ type: "success"
+ });
};
const handleDelete = (index: number, row) => {
- message(`您删除了第 ${index} 行,数据为:${JSON.stringify(row)}`, "info");
+ message(`您删除了第 ${index} 行,数据为:${JSON.stringify(row)}`);
};
const columns: TableColumnList = [
diff --git a/src/views/pure-table/high.vue b/src/views/pure-table/high.vue
index ef011f828..7f978207d 100644
--- a/src/views/pure-table/high.vue
+++ b/src/views/pure-table/high.vue
@@ -68,4 +68,15 @@ function tabClick({ index }) {
:deep(.el-alert__title) {
font-size: 16px;
}
+
+:deep(.el-tabs__nav-next),
+:deep(.el-tabs__nav-prev) {
+ font-size: 16px;
+ color: var(--el-text-color-primary);
+}
+
+:deep(.el-tabs__nav-next.is-disabled),
+:deep(.el-tabs__nav-prev.is-disabled) {
+ opacity: 0.5;
+}
diff --git a/src/views/pure-table/high/contextmenu/columns.tsx b/src/views/pure-table/high/contextmenu/columns.tsx
index 3ab9e2f0c..5a791618a 100644
--- a/src/views/pure-table/high/contextmenu/columns.tsx
+++ b/src/views/pure-table/high/contextmenu/columns.tsx
@@ -37,7 +37,9 @@ export function useColumns() {
`您编辑了第 ${
dataList.value.findIndex(v => v.id === row.id) + 1
} 行,数据为:${JSON.stringify(row)}`,
- "success"
+ {
+ type: "success"
+ }
)
}
]
diff --git a/src/views/pure-table/high/echarts/columns.tsx b/src/views/pure-table/high/echarts/columns.tsx
index 8d7c77546..8095e322f 100644
--- a/src/views/pure-table/high/echarts/columns.tsx
+++ b/src/views/pure-table/high/echarts/columns.tsx
@@ -78,7 +78,9 @@ export function useColumns() {
callback: ({ data: { name, value } }) => {
message(
`您点击了第 ${i + 1} 行,图表标题为${name},图表数据为:${value}`,
- "success"
+ {
+ type: "success"
+ }
);
}
}
diff --git a/src/views/pure-table/high/edit/columns.tsx b/src/views/pure-table/high/edit/columns.tsx
index e1cd80657..befd978d4 100644
--- a/src/views/pure-table/high/edit/columns.tsx
+++ b/src/views/pure-table/high/edit/columns.tsx
@@ -113,7 +113,9 @@ export function useColumns() {
`您编辑了第 ${index + 1} 行,编辑后数据为:${JSON.stringify(
dataList.value[index]
)}`,
- "success"
+ {
+ type: "success"
+ }
);
// 编辑状态关闭
editStatus.value[index] = Object.assign({}, editStatus.value[index], {
diff --git a/src/views/pure-table/high/execl/columns.tsx b/src/views/pure-table/high/execl/columns.tsx
index d028265d7..7ddcb1ac2 100644
--- a/src/views/pure-table/high/execl/columns.tsx
+++ b/src/views/pure-table/high/execl/columns.tsx
@@ -39,7 +39,9 @@ export function useColumns() {
const workBook = utils.book_new();
utils.book_append_sheet(workBook, workSheet, "数据报表");
writeFile(workBook, "pure-admin-table.xlsx");
- message("导出成功", "success");
+ message("导出成功", {
+ type: "success"
+ });
};
return {
diff --git a/src/views/pure-table/index.vue b/src/views/pure-table/index.vue
index e9ec2b5c2..dcf3716c1 100644
--- a/src/views/pure-table/index.vue
+++ b/src/views/pure-table/index.vue
@@ -62,4 +62,15 @@ defineOptions({
:deep(.el-alert__title) {
font-size: 16px;
}
+
+:deep(.el-tabs__nav-next),
+:deep(.el-tabs__nav-prev) {
+ font-size: 16px;
+ color: var(--el-text-color-primary);
+}
+
+:deep(.el-tabs__nav-next.is-disabled),
+:deep(.el-tabs__nav-prev.is-disabled) {
+ opacity: 0.5;
+}
diff --git a/src/views/system/role/columns.tsx b/src/views/system/role/columns.tsx
index 9849d0323..e37e90d7c 100644
--- a/src/views/system/role/columns.tsx
+++ b/src/views/system/role/columns.tsx
@@ -113,7 +113,9 @@ export function useColumns() {
loading: false
}
);
- message("已成功修改角色状态", "success");
+ message("已成功修改角色状态", {
+ type: "success"
+ });
}, 300);
})
.catch(() => {
diff --git a/src/views/system/user/columns.tsx b/src/views/system/user/columns.tsx
index dda65a04f..2ef28e2da 100644
--- a/src/views/system/user/columns.tsx
+++ b/src/views/system/user/columns.tsx
@@ -118,7 +118,9 @@ export function useColumns() {
loading: false
}
);
- message("已成功修改用户状态", "success");
+ message("已成功修改用户状态", {
+ type: "success"
+ });
}, 300);
})
.catch(() => {
diff --git a/tsconfig.json b/tsconfig.json
index 0cb30b9a7..4252509a9 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -29,7 +29,8 @@
"element-plus/global",
"@pureadmin/table/volar",
"@pureadmin/descriptions/volar",
- "unplugin-vue-macros/macros-global"
+ "unplugin-vue-macros/macros-global",
+ "unplugin-vue-define-options/macros-global"
],
"typeRoots": ["./node_modules/@types/", "./types"]
},