feat(工具类): 新增消息提示和主题色工具
- message: 封装统一的消息提示API(支持info/success/warning/error) - notification: 封装通知API - modal: 封装对话框API(支持confirm/prompt) - initThemeColor: 主题色初始化工具 - 完善TypeScript类型定义
This commit is contained in:
parent
a495a3c115
commit
02c00222d9
22
src/utils/initThemeColor.ts
Normal file
22
src/utils/initThemeColor.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { generate, getRgbStr } from '@arco-design/color';
|
||||
|
||||
/**
|
||||
* 初始化主题色 - 生成并注入完整的10个梯度色CSS变量
|
||||
* @param themeColor 主题色(HEX格式,如 #006266)
|
||||
* @param isDark 是否为暗色模式
|
||||
*/
|
||||
export function initThemeColor(themeColor: string, isDark = false) {
|
||||
// 使用 Arco Design 的颜色生成算法生成10个梯度色
|
||||
const colorList = generate(themeColor, {
|
||||
list: true,
|
||||
dark: isDark,
|
||||
});
|
||||
|
||||
// 将生成的梯度色注入到 document.body 的 CSS 变量中
|
||||
colorList.forEach((color, index) => {
|
||||
const rgbStr = getRgbStr(color);
|
||||
document.body.style.setProperty(`--arcoblue-${index + 1}`, rgbStr);
|
||||
});
|
||||
}
|
||||
|
||||
export default initThemeColor;
|
||||
598
src/utils/message/README.md
Normal file
598
src/utils/message/README.md
Normal file
@ -0,0 +1,598 @@
|
||||
# 消息提示工具类使用文档
|
||||
|
||||
这是一个基于 Arco Design 封装的统一消息提示工具类,提供了 Message、Notification 和 Modal 三种类型的 API,用于在 React 应用中展示各种提示信息。
|
||||
|
||||
## 特性
|
||||
|
||||
✅ **统一的 API 设计** - 提供一致的调用方式,降低学习成本
|
||||
✅ **完整的 TypeScript 支持** - 提供完整的类型定义
|
||||
✅ **Promise 化** - Modal API 支持 Promise,方便异步处理
|
||||
✅ **主题自适应** - 自动适配系统主题(亮色/暗色模式)
|
||||
✅ **错误处理** - 内置完善的错误处理机制
|
||||
✅ **易于使用** - 简洁的 API 设计,开箱即用
|
||||
|
||||
## 安装
|
||||
|
||||
该工具类已经集成在项目中,无需额外安装。直接导入使用即可:
|
||||
|
||||
```typescript
|
||||
import { message, notification, modal } from '@/utils/message';
|
||||
// 或者
|
||||
import coiMessage from '@/utils/message';
|
||||
```
|
||||
|
||||
## API 文档
|
||||
|
||||
### Message API
|
||||
|
||||
用于显示轻量级的提示信息,默认 3 秒后自动关闭。
|
||||
|
||||
#### 基础用法
|
||||
|
||||
```typescript
|
||||
import { message } from '@/utils/message';
|
||||
|
||||
// 信息提示
|
||||
message.info('这是一条信息提示');
|
||||
|
||||
// 成功提示
|
||||
message.success('操作成功!');
|
||||
|
||||
// 警告提示
|
||||
message.warning('请注意!');
|
||||
|
||||
// 错误提示
|
||||
message.error('操作失败,请重试');
|
||||
```
|
||||
|
||||
#### 自定义配置
|
||||
|
||||
```typescript
|
||||
// 自定义显示时长
|
||||
message.success('保存成功', { duration: 5000 });
|
||||
|
||||
// 显示关闭按钮
|
||||
message.info('这是一条可以手动关闭的消息', { closable: true });
|
||||
|
||||
// 关闭回调
|
||||
message.success('操作成功', {
|
||||
duration: 2000,
|
||||
onClose: () => {
|
||||
console.log('消息已关闭');
|
||||
},
|
||||
});
|
||||
|
||||
// 自定义图标
|
||||
import { IconCheckCircle } from '@arco-design/web-react/icon';
|
||||
|
||||
message.success('自定义图标', {
|
||||
icon: <IconCheckCircle />,
|
||||
});
|
||||
```
|
||||
|
||||
#### 手动关闭
|
||||
|
||||
```typescript
|
||||
// 获取消息实例,手动控制关闭
|
||||
const instance = message.info('这是一条消息', { duration: 0 });
|
||||
|
||||
// 3 秒后手动关闭
|
||||
setTimeout(() => {
|
||||
instance.close();
|
||||
}, 3000);
|
||||
```
|
||||
|
||||
#### 清空所有消息
|
||||
|
||||
```typescript
|
||||
// 清空所有正在显示的消息
|
||||
message.clear();
|
||||
```
|
||||
|
||||
#### MessageOptions 配置项
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| -------- | ---------------------------------- | ---------- | ------ |
|
||||
| duration | 显示时长(毫秒),0 表示不自动关闭 | number | 3000 |
|
||||
| closable | 是否显示关闭按钮 | boolean | false |
|
||||
| onClose | 关闭回调 | () => void | - |
|
||||
| icon | 自定义图标 | ReactNode | - |
|
||||
| id | 唯一标识 | string | - |
|
||||
|
||||
---
|
||||
|
||||
### Notification API
|
||||
|
||||
用于显示通知提醒消息,相比 Message 可以展示更多内容,默认 4.5 秒后自动关闭。
|
||||
|
||||
#### 基础用法
|
||||
|
||||
```typescript
|
||||
import { notification } from '@/utils/message';
|
||||
|
||||
// 信息通知
|
||||
notification.info({
|
||||
title: '通知标题',
|
||||
content: '这是通知内容',
|
||||
});
|
||||
|
||||
// 成功通知
|
||||
notification.success({
|
||||
title: '操作成功',
|
||||
content: '您的数据已保存',
|
||||
});
|
||||
|
||||
// 警告通知
|
||||
notification.warning({
|
||||
title: '警告',
|
||||
content: '您的账户即将到期',
|
||||
});
|
||||
|
||||
// 错误通知
|
||||
notification.error({
|
||||
title: '错误',
|
||||
content: '网络连接失败,请检查您的网络设置',
|
||||
});
|
||||
```
|
||||
|
||||
#### 自定义配置
|
||||
|
||||
```typescript
|
||||
// 自定义位置
|
||||
notification.success({
|
||||
title: '保存成功',
|
||||
content: '数据已成功保存',
|
||||
position: 'topLeft', // topLeft, topRight, bottomLeft, bottomRight
|
||||
});
|
||||
|
||||
// 自定义显示时长
|
||||
notification.info({
|
||||
title: '提示',
|
||||
content: '这条通知将显示 10 秒',
|
||||
duration: 10000,
|
||||
});
|
||||
|
||||
// 不自动关闭
|
||||
notification.warning({
|
||||
title: '重要提示',
|
||||
content: '请注意查看',
|
||||
duration: 0,
|
||||
closable: true,
|
||||
});
|
||||
|
||||
// 关闭回调
|
||||
notification.success({
|
||||
title: '上传完成',
|
||||
content: '文件已成功上传',
|
||||
onClose: () => {
|
||||
console.log('通知已关闭');
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
#### 手动关闭
|
||||
|
||||
```typescript
|
||||
// 获取通知实例,手动控制关闭
|
||||
const instance = notification.info({
|
||||
title: '通知',
|
||||
content: '这是一条通知',
|
||||
duration: 0,
|
||||
});
|
||||
|
||||
// 5 秒后手动关闭
|
||||
setTimeout(() => {
|
||||
instance.close();
|
||||
}, 5000);
|
||||
```
|
||||
|
||||
#### 清空所有通知
|
||||
|
||||
```typescript
|
||||
// 清空所有正在显示的通知
|
||||
notification.clear();
|
||||
```
|
||||
|
||||
#### NotificationOptions 配置项
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| -------- | ---------------------------------- | -------------------------------------------------------- | ---------- |
|
||||
| title | 标题 | ReactNode | - |
|
||||
| content | 内容 | ReactNode | 必填 |
|
||||
| duration | 显示时长(毫秒),0 表示不自动关闭 | number | 4500 |
|
||||
| closable | 是否显示关闭按钮 | boolean | false |
|
||||
| onClose | 关闭回调 | () => void | - |
|
||||
| icon | 自定义图标 | ReactNode | - |
|
||||
| id | 唯一标识 | string | - |
|
||||
| position | 位置 | 'topLeft' \| 'topRight' \| 'bottomLeft' \| 'bottomRight' | 'topRight' |
|
||||
|
||||
---
|
||||
|
||||
### Modal API
|
||||
|
||||
用于显示对话框,支持确认、提示、输入等多种场景。所有方法都返回 Promise。
|
||||
|
||||
#### 确认对话框
|
||||
|
||||
```typescript
|
||||
import { modal } from '@/utils/message';
|
||||
|
||||
// 基础确认
|
||||
const result = await modal.confirm({
|
||||
title: '确认删除',
|
||||
content: '确定要删除这条记录吗?此操作不可恢复。',
|
||||
});
|
||||
|
||||
if (result) {
|
||||
console.log('用户点击了确定');
|
||||
} else {
|
||||
console.log('用户点击了取消');
|
||||
}
|
||||
|
||||
// 自定义按钮文本
|
||||
modal.confirm({
|
||||
title: '确认提交',
|
||||
content: '确定要提交表单吗?',
|
||||
okText: '提交',
|
||||
cancelText: '再想想',
|
||||
onOk: async () => {
|
||||
// 异步操作
|
||||
await submitForm();
|
||||
message.success('提交成功');
|
||||
},
|
||||
onCancel: () => {
|
||||
message.info('已取消提交');
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
#### 信息提示对话框
|
||||
|
||||
```typescript
|
||||
// 信息提示
|
||||
modal.info({
|
||||
title: '提示',
|
||||
content: '这是一条信息提示',
|
||||
});
|
||||
|
||||
// 成功提示
|
||||
modal.success({
|
||||
title: '操作成功',
|
||||
content: '您的操作已成功完成!',
|
||||
});
|
||||
|
||||
// 警告提示
|
||||
modal.warning({
|
||||
title: '警告',
|
||||
content: '您的账户即将到期,请及时续费',
|
||||
});
|
||||
|
||||
// 错误提示
|
||||
modal.error({
|
||||
title: '错误',
|
||||
content: '操作失败,请稍后重试',
|
||||
});
|
||||
|
||||
// 简单提示(alert 是 warning 的别名)
|
||||
modal.alert({
|
||||
title: '提示',
|
||||
content: '请注意查看',
|
||||
});
|
||||
```
|
||||
|
||||
#### 输入对话框
|
||||
|
||||
```typescript
|
||||
// 基础输入
|
||||
const value = await modal.prompt({
|
||||
title: '请输入名称',
|
||||
placeholder: '请输入您的名称',
|
||||
defaultValue: '',
|
||||
});
|
||||
|
||||
if (value !== null) {
|
||||
console.log('用户输入:', value);
|
||||
} else {
|
||||
console.log('用户取消了输入');
|
||||
}
|
||||
|
||||
// 必填校验
|
||||
const username = await modal.prompt({
|
||||
title: '修改用户名',
|
||||
placeholder: '请输入新的用户名',
|
||||
required: true,
|
||||
defaultValue: 'admin',
|
||||
});
|
||||
|
||||
// 自定义校验
|
||||
const email = await modal.prompt({
|
||||
title: '请输入邮箱',
|
||||
placeholder: '请输入您的邮箱地址',
|
||||
required: true,
|
||||
validator: (value) => {
|
||||
const emailReg = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
if (!emailReg.test(value)) {
|
||||
return '请输入正确的邮箱格式';
|
||||
}
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
// 密码输入
|
||||
const password = await modal.prompt({
|
||||
title: '请输入密码',
|
||||
inputType: 'password',
|
||||
placeholder: '请输入密码',
|
||||
required: true,
|
||||
});
|
||||
|
||||
// 多行文本输入
|
||||
const description = await modal.prompt({
|
||||
title: '请输入描述',
|
||||
inputType: 'textarea',
|
||||
placeholder: '请输入描述信息',
|
||||
content: '描述信息将显示在产品详情页',
|
||||
});
|
||||
|
||||
// 完整示例:带异步处理和错误处理
|
||||
const name = await modal.prompt({
|
||||
title: '修改项目名称',
|
||||
content: '请输入新的项目名称',
|
||||
placeholder: '项目名称',
|
||||
defaultValue: '我的项目',
|
||||
required: true,
|
||||
validator: (value) => {
|
||||
if (value.length < 2) {
|
||||
return '项目名称至少 2 个字符';
|
||||
}
|
||||
if (value.length > 50) {
|
||||
return '项目名称不能超过 50 个字符';
|
||||
}
|
||||
return true;
|
||||
},
|
||||
onOk: async () => {
|
||||
// 可以在这里执行异步操作
|
||||
await updateProjectName(name);
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
#### 自定义配置
|
||||
|
||||
```typescript
|
||||
// 自定义宽度
|
||||
modal.confirm({
|
||||
title: '确认操作',
|
||||
content: '这是一个宽度为 600px 的对话框',
|
||||
width: 600,
|
||||
});
|
||||
|
||||
// 自定义按钮属性
|
||||
modal.confirm({
|
||||
title: '危险操作',
|
||||
content: '确定要执行此危险操作吗?',
|
||||
okButtonProps: {
|
||||
status: 'danger',
|
||||
},
|
||||
cancelButtonProps: {
|
||||
type: 'outline',
|
||||
},
|
||||
});
|
||||
|
||||
// 点击遮罩层不关闭
|
||||
modal.confirm({
|
||||
title: '重要确认',
|
||||
content: '请认真阅读并确认',
|
||||
maskClosable: false,
|
||||
});
|
||||
|
||||
// 隐藏取消按钮
|
||||
modal.confirm({
|
||||
title: '温馨提示',
|
||||
content: '系统将在 5 分钟后进行维护',
|
||||
showCancel: false,
|
||||
});
|
||||
```
|
||||
|
||||
#### 销毁所有对话框
|
||||
|
||||
```typescript
|
||||
// 销毁所有正在显示的对话框
|
||||
modal.destroyAll();
|
||||
```
|
||||
|
||||
#### ModalOptions 配置项
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| ----------------- | ------------------ | --------------------------- | ------ |
|
||||
| title | 标题 | ReactNode | - |
|
||||
| content | 内容 | ReactNode | 必填 |
|
||||
| okText | 确定按钮文本 | string | '确定' |
|
||||
| cancelText | 取消按钮文本 | string | '取消' |
|
||||
| okButtonProps | 确定按钮属性 | any | - |
|
||||
| cancelButtonProps | 取消按钮属性 | any | - |
|
||||
| onOk | 点击确定的回调 | () => void \| Promise<void> | - |
|
||||
| onCancel | 点击取消的回调 | () => void | - |
|
||||
| width | 宽度 | number \| string | - |
|
||||
| showCancel | 是否显示取消按钮 | boolean | true |
|
||||
| icon | 自定义图标 | ReactNode | - |
|
||||
| maskClosable | 遮罩是否可点击关闭 | boolean | true |
|
||||
|
||||
#### PromptOptions 配置项
|
||||
|
||||
在 ModalOptions 基础上增加以下配置:
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| ------------ | ---------------- | ------------------------------------ | -------- |
|
||||
| content | 提示内容(可选) | ReactNode | - |
|
||||
| placeholder | 输入框占位符 | string | '请输入' |
|
||||
| defaultValue | 默认值 | string | '' |
|
||||
| inputType | 输入框类型 | 'text' \| 'password' \| 'textarea' | 'text' |
|
||||
| validator | 验证规则 | (value: string) => boolean \| string | - |
|
||||
| required | 是否必填 | boolean | false |
|
||||
|
||||
---
|
||||
|
||||
## 完整示例
|
||||
|
||||
### 示例 1:删除确认
|
||||
|
||||
```typescript
|
||||
import { modal, message } from '@/utils/message';
|
||||
|
||||
async function handleDelete(id: string) {
|
||||
const confirmed = await modal.confirm({
|
||||
title: '确认删除',
|
||||
content: '确定要删除这条记录吗?此操作不可恢复。',
|
||||
okText: '确定删除',
|
||||
cancelText: '取消',
|
||||
okButtonProps: {
|
||||
status: 'danger',
|
||||
},
|
||||
});
|
||||
|
||||
if (confirmed) {
|
||||
try {
|
||||
await deleteRecord(id);
|
||||
message.success('删除成功');
|
||||
} catch (error) {
|
||||
message.error('删除失败,请重试');
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 示例 2:表单保存提示
|
||||
|
||||
```typescript
|
||||
import { message, notification } from '@/utils/message';
|
||||
|
||||
async function handleSubmit(formData: any) {
|
||||
// 显示加载消息
|
||||
const loadingMsg = message.info('正在保存...', { duration: 0 });
|
||||
|
||||
try {
|
||||
await saveForm(formData);
|
||||
|
||||
// 关闭加载消息
|
||||
loadingMsg.close();
|
||||
|
||||
// 显示成功通知
|
||||
notification.success({
|
||||
title: '保存成功',
|
||||
content: '您的数据已成功保存',
|
||||
duration: 3000,
|
||||
});
|
||||
} catch (error) {
|
||||
// 关闭加载消息
|
||||
loadingMsg.close();
|
||||
|
||||
// 显示错误消息
|
||||
message.error('保存失败,请重试');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 示例 3:输入对话框
|
||||
|
||||
```typescript
|
||||
import { modal, message } from '@/utils/message';
|
||||
|
||||
async function handleRename(id: string, currentName: string) {
|
||||
const newName = await modal.prompt({
|
||||
title: '重命名',
|
||||
content: '请输入新的名称',
|
||||
placeholder: '请输入名称',
|
||||
defaultValue: currentName,
|
||||
required: true,
|
||||
validator: (value) => {
|
||||
if (value.length < 2) {
|
||||
return '名称至少 2 个字符';
|
||||
}
|
||||
if (value.length > 20) {
|
||||
return '名称不能超过 20 个字符';
|
||||
}
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
if (newName !== null && newName !== currentName) {
|
||||
try {
|
||||
await updateName(id, newName);
|
||||
message.success('重命名成功');
|
||||
} catch (error) {
|
||||
message.error('重命名失败');
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 示例 4:批量操作确认
|
||||
|
||||
```typescript
|
||||
import { modal, message } from '@/utils/message';
|
||||
|
||||
async function handleBatchDelete(selectedIds: string[]) {
|
||||
if (selectedIds.length === 0) {
|
||||
message.warning('请先选择要删除的项目');
|
||||
return;
|
||||
}
|
||||
|
||||
const confirmed = await modal.confirm({
|
||||
title: '批量删除确认',
|
||||
content: `确定要删除选中的 ${selectedIds.length} 项记录吗?此操作不可恢复。`,
|
||||
okText: `删除 ${selectedIds.length} 项`,
|
||||
cancelText: '取消',
|
||||
okButtonProps: {
|
||||
status: 'danger',
|
||||
},
|
||||
});
|
||||
|
||||
if (confirmed) {
|
||||
const loadingMsg = message.info('正在删除...', { duration: 0 });
|
||||
|
||||
try {
|
||||
await batchDelete(selectedIds);
|
||||
loadingMsg.close();
|
||||
message.success(`成功删除 ${selectedIds.length} 项记录`);
|
||||
} catch (error) {
|
||||
loadingMsg.close();
|
||||
message.error('删除失败,请重试');
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **Message 和 Notification 的区别**
|
||||
|
||||
- Message:轻量级提示,适合简短的反馈信息
|
||||
- Notification:通知提醒,适合需要标题和详细内容的场景
|
||||
|
||||
2. **Modal Promise 返回值**
|
||||
|
||||
- `confirm`、`warning`、`alert` 返回 `boolean`,true 表示确定,false 表示取消
|
||||
- `info`、`success`、`error` 返回 `boolean`,通常只返回 true(点击确定)
|
||||
- `prompt` 返回 `string | null`,string 表示用户输入,null 表示取消
|
||||
|
||||
3. **异步操作处理**
|
||||
|
||||
- `onOk` 回调支持 `Promise`,会自动处理 loading 状态
|
||||
- 如果 `onOk` 抛出异常,对话框不会关闭
|
||||
|
||||
4. **样式和主题**
|
||||
|
||||
- 组件会自动适配系统主题(亮色/暗色模式)
|
||||
- 使用 CSS 变量实现主题色适配
|
||||
|
||||
5. **性能优化**
|
||||
- 避免在循环中频繁调用 Message API
|
||||
- 使用 `message.clear()` 可以清空所有正在显示的消息
|
||||
|
||||
## 相关链接
|
||||
|
||||
- [Arco Design 官方文档](https://arco.design/)
|
||||
- [Message 组件文档](https://arco.design/react/components/message)
|
||||
- [Notification 组件文档](https://arco.design/react/components/notification)
|
||||
- [Modal 组件文档](https://arco.design/react/components/modal)
|
||||
520
src/utils/message/index.ts
Normal file
520
src/utils/message/index.ts
Normal file
@ -0,0 +1,520 @@
|
||||
import {
|
||||
Message as ArcoMessage,
|
||||
Notification as ArcoNotification,
|
||||
Modal as ArcoModal,
|
||||
} from '@arco-design/web-react';
|
||||
import type {
|
||||
MessageType,
|
||||
MessageOptions,
|
||||
MessageInstance,
|
||||
NotificationOptions,
|
||||
NotificationInstance,
|
||||
ModalOptions,
|
||||
PromptOptions,
|
||||
} from './types';
|
||||
|
||||
/**
|
||||
* Message API 实现
|
||||
*/
|
||||
class MessageAPI {
|
||||
private defaultDuration = 3000;
|
||||
|
||||
/**
|
||||
* 显示消息的通用方法
|
||||
*/
|
||||
private show(
|
||||
type: MessageType,
|
||||
content: string,
|
||||
options?: MessageOptions
|
||||
): MessageInstance {
|
||||
const { duration = this.defaultDuration, ...restOptions } = options || {};
|
||||
|
||||
const closeFunc = ArcoMessage[type]({
|
||||
content,
|
||||
duration,
|
||||
...restOptions,
|
||||
});
|
||||
|
||||
return {
|
||||
close: () => {
|
||||
if (typeof closeFunc === 'function') {
|
||||
closeFunc();
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示信息提示
|
||||
*/
|
||||
info(content: string, options?: MessageOptions): MessageInstance {
|
||||
return this.show('info', content, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示成功提示
|
||||
*/
|
||||
success(content: string, options?: MessageOptions): MessageInstance {
|
||||
return this.show('success', content, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示警告提示
|
||||
*/
|
||||
warning(content: string, options?: MessageOptions): MessageInstance {
|
||||
return this.show('warning', content, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示错误提示
|
||||
*/
|
||||
error(content: string, options?: MessageOptions): MessageInstance {
|
||||
return this.show('error', content, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空所有消息
|
||||
*/
|
||||
clear(): void {
|
||||
ArcoMessage.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notification API 实现
|
||||
*/
|
||||
class NotificationAPI {
|
||||
private defaultDuration = 4500;
|
||||
private defaultPosition: NotificationOptions['position'] = 'topRight';
|
||||
|
||||
/**
|
||||
* 显示通知的通用方法
|
||||
*/
|
||||
private show(
|
||||
type: MessageType,
|
||||
options: NotificationOptions
|
||||
): NotificationInstance {
|
||||
const {
|
||||
duration = this.defaultDuration,
|
||||
position = this.defaultPosition,
|
||||
...restOptions
|
||||
} = options;
|
||||
|
||||
const closeFunc = ArcoNotification[type]({
|
||||
duration,
|
||||
position,
|
||||
...restOptions,
|
||||
});
|
||||
|
||||
return {
|
||||
close: () => {
|
||||
if (typeof closeFunc === 'function') {
|
||||
closeFunc();
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示信息通知
|
||||
*/
|
||||
info(options: NotificationOptions): NotificationInstance {
|
||||
return this.show('info', options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示成功通知
|
||||
*/
|
||||
success(options: NotificationOptions): NotificationInstance {
|
||||
return this.show('success', options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示警告通知
|
||||
*/
|
||||
warning(options: NotificationOptions): NotificationInstance {
|
||||
return this.show('warning', options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示错误通知
|
||||
*/
|
||||
error(options: NotificationOptions): NotificationInstance {
|
||||
return this.show('error', options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空所有通知
|
||||
*/
|
||||
clear(): void {
|
||||
ArcoNotification.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Modal API 实现
|
||||
*/
|
||||
class ModalAPI {
|
||||
/**
|
||||
* 确认对话框
|
||||
*/
|
||||
confirm(options: ModalOptions): Promise<boolean> {
|
||||
return new Promise((resolve) => {
|
||||
const {
|
||||
title = '确认',
|
||||
content,
|
||||
okText = '确定',
|
||||
cancelText = '取消',
|
||||
showCancel = true,
|
||||
onOk,
|
||||
onCancel,
|
||||
...restOptions
|
||||
} = options;
|
||||
|
||||
ArcoModal.confirm({
|
||||
title,
|
||||
content,
|
||||
okText,
|
||||
cancelText,
|
||||
...restOptions,
|
||||
onOk: async () => {
|
||||
try {
|
||||
if (onOk) {
|
||||
await onOk();
|
||||
}
|
||||
resolve(true);
|
||||
} catch (error) {
|
||||
console.error('Modal confirm onOk error:', error);
|
||||
resolve(false);
|
||||
}
|
||||
},
|
||||
onCancel: () => {
|
||||
onCancel?.();
|
||||
resolve(false);
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 信息提示对话框
|
||||
*/
|
||||
info(options: ModalOptions): Promise<boolean> {
|
||||
return new Promise((resolve) => {
|
||||
const {
|
||||
title = '提示',
|
||||
content,
|
||||
okText = '确定',
|
||||
onOk,
|
||||
...restOptions
|
||||
} = options;
|
||||
|
||||
ArcoModal.info({
|
||||
title,
|
||||
content,
|
||||
okText,
|
||||
...restOptions,
|
||||
onOk: async () => {
|
||||
try {
|
||||
if (onOk) {
|
||||
await onOk();
|
||||
}
|
||||
resolve(true);
|
||||
} catch (error) {
|
||||
console.error('Modal info onOk error:', error);
|
||||
resolve(false);
|
||||
}
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 成功提示对话框
|
||||
*/
|
||||
success(options: ModalOptions): Promise<boolean> {
|
||||
return new Promise((resolve) => {
|
||||
const {
|
||||
title = '成功',
|
||||
content,
|
||||
okText = '确定',
|
||||
onOk,
|
||||
...restOptions
|
||||
} = options;
|
||||
|
||||
ArcoModal.success({
|
||||
title,
|
||||
content,
|
||||
okText,
|
||||
...restOptions,
|
||||
onOk: async () => {
|
||||
try {
|
||||
if (onOk) {
|
||||
await onOk();
|
||||
}
|
||||
resolve(true);
|
||||
} catch (error) {
|
||||
console.error('Modal success onOk error:', error);
|
||||
resolve(false);
|
||||
}
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 警告提示对话框
|
||||
*/
|
||||
warning(options: ModalOptions): Promise<boolean> {
|
||||
return new Promise((resolve) => {
|
||||
const {
|
||||
title = '警告',
|
||||
content,
|
||||
okText = '确定',
|
||||
cancelText = '取消',
|
||||
showCancel = true,
|
||||
onOk,
|
||||
onCancel,
|
||||
...restOptions
|
||||
} = options;
|
||||
|
||||
ArcoModal.warning({
|
||||
title,
|
||||
content,
|
||||
okText,
|
||||
cancelText,
|
||||
...restOptions,
|
||||
onOk: async () => {
|
||||
try {
|
||||
if (onOk) {
|
||||
await onOk();
|
||||
}
|
||||
resolve(true);
|
||||
} catch (error) {
|
||||
console.error('Modal warning onOk error:', error);
|
||||
resolve(false);
|
||||
}
|
||||
},
|
||||
onCancel: () => {
|
||||
onCancel?.();
|
||||
resolve(false);
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 错误提示对话框
|
||||
*/
|
||||
error(options: ModalOptions): Promise<boolean> {
|
||||
return new Promise((resolve) => {
|
||||
const {
|
||||
title = '错误',
|
||||
content,
|
||||
okText = '确定',
|
||||
onOk,
|
||||
...restOptions
|
||||
} = options;
|
||||
|
||||
ArcoModal.error({
|
||||
title,
|
||||
content,
|
||||
okText,
|
||||
...restOptions,
|
||||
onOk: async () => {
|
||||
try {
|
||||
if (onOk) {
|
||||
await onOk();
|
||||
}
|
||||
resolve(true);
|
||||
} catch (error) {
|
||||
console.error('Modal error onOk error:', error);
|
||||
resolve(false);
|
||||
}
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 警告对话框(别名)
|
||||
*/
|
||||
alert(options: ModalOptions): Promise<boolean> {
|
||||
return this.warning(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 输入提示对话框
|
||||
*/
|
||||
prompt(options: PromptOptions): Promise<string | null> {
|
||||
return new Promise((resolve) => {
|
||||
const {
|
||||
title = '输入',
|
||||
content,
|
||||
okText = '确定',
|
||||
cancelText = '取消',
|
||||
placeholder = '请输入',
|
||||
defaultValue = '',
|
||||
inputType = 'text',
|
||||
validator,
|
||||
required = false,
|
||||
onOk,
|
||||
onCancel,
|
||||
...restOptions
|
||||
} = options;
|
||||
|
||||
let inputValue = defaultValue;
|
||||
let errorMessage = '';
|
||||
|
||||
const validateInput = (): boolean => {
|
||||
// 必填校验
|
||||
if (required && !inputValue.trim()) {
|
||||
errorMessage = '此项为必填项';
|
||||
return false;
|
||||
}
|
||||
|
||||
// 自定义校验
|
||||
if (validator) {
|
||||
const result = validator(inputValue);
|
||||
if (result === false) {
|
||||
errorMessage = '输入格式不正确';
|
||||
return false;
|
||||
}
|
||||
if (typeof result === 'string') {
|
||||
errorMessage = result;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
errorMessage = '';
|
||||
return true;
|
||||
};
|
||||
|
||||
// 创建输入框内容
|
||||
const renderContent = () => {
|
||||
const container = document.createElement('div');
|
||||
|
||||
// 如果有提示内容,先显示提示内容
|
||||
if (content) {
|
||||
const contentDiv = document.createElement('div');
|
||||
contentDiv.style.marginBottom = '12px';
|
||||
if (typeof content === 'string') {
|
||||
contentDiv.textContent = content;
|
||||
}
|
||||
container.appendChild(contentDiv);
|
||||
}
|
||||
|
||||
// 创建输入框
|
||||
const input = document.createElement(
|
||||
inputType === 'textarea' ? 'textarea' : 'input'
|
||||
);
|
||||
input.className = 'arco-input';
|
||||
input.placeholder = placeholder;
|
||||
input.value = defaultValue;
|
||||
input.style.width = '100%';
|
||||
|
||||
if (inputType === 'password') {
|
||||
(input as HTMLInputElement).type = 'password';
|
||||
}
|
||||
|
||||
if (inputType === 'textarea') {
|
||||
(input as HTMLTextAreaElement).rows = 4;
|
||||
input.className = 'arco-textarea';
|
||||
}
|
||||
|
||||
input.addEventListener('input', (e) => {
|
||||
inputValue = (e.target as HTMLInputElement | HTMLTextAreaElement)
|
||||
.value;
|
||||
// 清除错误信息
|
||||
if (errorDiv.textContent) {
|
||||
errorDiv.textContent = '';
|
||||
errorDiv.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
container.appendChild(input);
|
||||
|
||||
// 创建错误提示
|
||||
const errorDiv = document.createElement('div');
|
||||
errorDiv.style.color = '#f53f3f';
|
||||
errorDiv.style.fontSize = '12px';
|
||||
errorDiv.style.marginTop = '8px';
|
||||
errorDiv.style.display = 'none';
|
||||
container.appendChild(errorDiv);
|
||||
|
||||
// 自动聚焦
|
||||
setTimeout(() => {
|
||||
input.focus();
|
||||
}, 100);
|
||||
|
||||
return { container, input, errorDiv };
|
||||
};
|
||||
|
||||
const { container, errorDiv } = renderContent();
|
||||
|
||||
ArcoModal.confirm({
|
||||
title,
|
||||
content: container as any,
|
||||
okText,
|
||||
cancelText,
|
||||
...restOptions,
|
||||
onOk: async () => {
|
||||
if (!validateInput()) {
|
||||
errorDiv.textContent = errorMessage;
|
||||
errorDiv.style.display = 'block';
|
||||
throw new Error(errorMessage); // 阻止对话框关闭
|
||||
}
|
||||
|
||||
try {
|
||||
if (onOk) {
|
||||
await onOk();
|
||||
}
|
||||
resolve(inputValue);
|
||||
} catch (error) {
|
||||
console.error('Modal prompt onOk error:', error);
|
||||
errorDiv.textContent =
|
||||
error instanceof Error ? error.message : '操作失败';
|
||||
errorDiv.style.display = 'block';
|
||||
throw error; // 阻止对话框关闭
|
||||
}
|
||||
},
|
||||
onCancel: () => {
|
||||
onCancel?.();
|
||||
resolve(null);
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁所有对话框
|
||||
*/
|
||||
destroyAll(): void {
|
||||
ArcoModal.destroyAll();
|
||||
}
|
||||
}
|
||||
|
||||
// 创建单例实例
|
||||
export const message = new MessageAPI();
|
||||
export const notification = new NotificationAPI();
|
||||
export const modal = new ModalAPI();
|
||||
|
||||
// 默认导出一个包含所有 API 的对象
|
||||
const coiMessage = {
|
||||
message,
|
||||
notification,
|
||||
modal,
|
||||
};
|
||||
|
||||
export default coiMessage;
|
||||
|
||||
// 导出类型
|
||||
export type {
|
||||
MessageType,
|
||||
MessageOptions,
|
||||
MessageInstance,
|
||||
NotificationOptions,
|
||||
NotificationInstance,
|
||||
ModalOptions,
|
||||
PromptOptions,
|
||||
} from './types';
|
||||
108
src/utils/message/types.ts
Normal file
108
src/utils/message/types.ts
Normal file
@ -0,0 +1,108 @@
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
/**
|
||||
* 消息类型
|
||||
*/
|
||||
export type MessageType = 'info' | 'success' | 'warning' | 'error';
|
||||
|
||||
/**
|
||||
* Message 配置选项
|
||||
*/
|
||||
export interface MessageOptions {
|
||||
/** 显示时长(毫秒),0 表示不自动关闭 */
|
||||
duration?: number;
|
||||
/** 是否显示关闭按钮 */
|
||||
closable?: boolean;
|
||||
/** 关闭回调 */
|
||||
onClose?: () => void;
|
||||
/** 自定义图标 */
|
||||
icon?: ReactNode;
|
||||
/** 唯一标识 */
|
||||
id?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notification 配置选项
|
||||
*/
|
||||
export interface NotificationOptions {
|
||||
/** 标题 */
|
||||
title?: ReactNode;
|
||||
/** 内容 */
|
||||
content: ReactNode;
|
||||
/** 显示时长(毫秒),0 表示不自动关闭 */
|
||||
duration?: number;
|
||||
/** 是否显示关闭按钮 */
|
||||
closable?: boolean;
|
||||
/** 关闭回调 */
|
||||
onClose?: () => void;
|
||||
/** 自定义图标 */
|
||||
icon?: ReactNode;
|
||||
/** 唯一标识 */
|
||||
id?: string;
|
||||
/** 位置 */
|
||||
position?: 'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight';
|
||||
}
|
||||
|
||||
/**
|
||||
* Modal 配置选项
|
||||
*/
|
||||
export interface ModalOptions {
|
||||
/** 标题 */
|
||||
title?: ReactNode;
|
||||
/** 内容 */
|
||||
content: ReactNode;
|
||||
/** 确定按钮文本 */
|
||||
okText?: string;
|
||||
/** 取消按钮文本 */
|
||||
cancelText?: string;
|
||||
/** 确定按钮类型 */
|
||||
okButtonProps?: any;
|
||||
/** 取消按钮类型 */
|
||||
cancelButtonProps?: any;
|
||||
/** 点击确定的回调 */
|
||||
onOk?: () => void | Promise<void>;
|
||||
/** 点击取消的回调 */
|
||||
onCancel?: () => void;
|
||||
/** 宽度 */
|
||||
width?: number | string;
|
||||
/** 是否显示取消按钮 */
|
||||
showCancel?: boolean;
|
||||
/** 自定义图标 */
|
||||
icon?: ReactNode;
|
||||
/** 遮罩是否可点击关闭 */
|
||||
maskClosable?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompt Modal 配置选项
|
||||
*/
|
||||
export interface PromptOptions extends Omit<ModalOptions, 'content'> {
|
||||
/** 提示内容 */
|
||||
content?: ReactNode;
|
||||
/** 输入框占位符 */
|
||||
placeholder?: string;
|
||||
/** 默认值 */
|
||||
defaultValue?: string;
|
||||
/** 输入框类型 */
|
||||
inputType?: 'text' | 'password' | 'textarea';
|
||||
/** 验证规则 */
|
||||
validator?: (value: string) => boolean | string;
|
||||
/** 是否必填 */
|
||||
required?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Message 实例返回类型
|
||||
*/
|
||||
export interface MessageInstance {
|
||||
/** 关闭当前消息 */
|
||||
close: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notification 实例返回类型
|
||||
*/
|
||||
export interface NotificationInstance {
|
||||
/** 关闭当前通知 */
|
||||
close: () => void;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user