弹窗服务 (pop)
@erp/biz 提供的统一弹窗服务,包含对话框、抽屉、消息提示、通知等功能。
功能概览
- 消息提示 - 轻量级反馈:
success/error/warning/info/loading - 通知提示 - 丰富通知:
succ/err/warn/inf - 确认对话框 - 用户确认:
confirm - Modal 弹窗 - 自定义内容:
createModal - Drawer 抽屉 - 侧边面板:
createDrawer - Page 页面 - 全屏组件:
createPage - 全局加载 - 加载遮罩:
spin
引入方式
typescript
import { pop } from '@erp/biz'初始化配置
在应用入口处初始化 pop 服务:
typescript
import { createApp } from 'vue'
import { pop } from '@erp/biz'
import router from './router'
import App from './App.vue'
const app = createApp(App)
// 初始化 pop 服务
pop.install(app, router, {
popupContainer: '#app', // 弹窗挂载容器
exchangeTime: true,
scrollToClose: false
})
app.mount('#app')消息提示
轻量级的消息反馈,显示在页面顶部,适用于操作结果的即时反馈。
pop.success
显示成功消息。
typescript
pop.success('操作成功')
// 自定义配置
pop.success({
content: '保存成功',
duration: 3000
})pop.error
显示错误消息。
typescript
pop.error('操作失败')
pop.error({
content: '网络错误,请重试',
duration: 5000
})pop.warning
显示警告消息。
typescript
pop.warning('请注意数据安全')pop.info
显示信息消息。
typescript
pop.info('这是一条提示信息')pop.loading
显示加载中消息,需手动关闭。
typescript
// 显示加载
const loading = pop.loading('正在处理...')
// 处理完成后关闭
await doSomething()
loading.close()
// 自定义配置
const loading = pop.loading({
content: '正在上传...',
duration: 0 // 0 表示不自动关闭
})MessageConfig
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| content | string | - | 消息内容 |
| duration | number | 3000 | 显示时长(ms),0 表示不自动关闭 |
| resetOnHover | boolean | true | 鼠标悬停时是否重置计时 |
| closable | boolean | false | 是否显示关闭按钮 |
通知提示
更丰富的通知消息,显示在页面角落,适用于需要用户关注的重要信息。
pop.succ
显示成功通知。
typescript
pop.succ('订单提交成功')
pop.succ({
title: '提交成功',
content: '您的订单已提交,请等待审核'
})pop.err
显示错误通知。
typescript
pop.err('系统异常')
pop.err({
title: '操作失败',
content: '服务器繁忙,请稍后重试',
duration: 5000
})pop.warn
显示警告通知。
typescript
pop.warn('库存不足')pop.inf
显示信息通知。
typescript
pop.inf('您有新的消息')NotificationConfig
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| title | string | '消息通知' | 通知标题 |
| content | string | - | 通知内容 |
| duration | number | 3000 | 显示时长(ms) |
| closable | boolean | true | 是否显示关闭按钮 |
| position | string | 'topRight' | 显示位置 |
确认对话框
用于需要用户确认的操作场景,如删除、提交等危险或重要操作。
pop.confirm
显示确认对话框,返回 Promise。
typescript
// 基础用法
try {
await pop.confirm('确定要删除吗?')
// 用户点击确定
await deleteItem()
pop.success('删除成功')
} catch {
// 用户点击取消
}
// 自定义配置
await pop.confirm('此操作不可恢复,确定继续?', {
title: '警告',
okText: '确定删除',
cancelText: '取消',
okButtonProps: { status: 'danger' }
})
// 手动关闭
const dialog = pop.confirm('处理中...')
await doSomething()
dialog.close()ModalConfig
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| title | string | '温馨提示' | 对话框标题 |
| content | string | VNode | - | 对话框内容 |
| okText | string | '确定' | 确定按钮文字 |
| cancelText | string | '取消' | 取消按钮文字 |
| closable | boolean | true | 是否显示关闭按钮 |
| maskClosable | boolean | true | 点击遮罩是否关闭 |
| width | number | string | 420 | 对话框宽度 |
| okButtonProps | object | - | 确定按钮属性 |
| cancelButtonProps | object | - | 取消按钮属性 |
Modal 弹窗
用于展示自定义内容的模态对话框,支持异步加载组件。
pop.createModal
打开 Modal 弹窗,加载自定义组件。
typescript
// 基础用法
const result = await pop.createModal(MyComponent, {
// 传递给组件的 props
id: 123,
name: '张三'
}, {
// Modal 配置
title: '编辑用户',
width: 600
})
// 异步加载组件
const result = await pop.createModal(
import('./EditUser.vue'),
{ id: 123 },
{ title: '编辑用户' }
)
// 使用 id 防止重复打开
await pop.createModal(MyComponent, params, {
id: 'edit-user-modal',
title: '编辑用户'
})
// 手动关闭
const modal = pop.createModal(MyComponent)
modal.close()组件内部使用
vue
<!-- EditUser.vue -->
<template>
<div>
<FkForm :model="form" />
</div>
</template>
<script setup lang="ts">
import { defineProps, defineEmits } from 'vue'
// 接收 pop.createModal 传入的参数
const props = defineProps<{
id: number
name: string
}>()
// 定义事件
const emit = defineEmits<{
(e: 'ok', data: any): void
(e: 'close'): void
(e: 'loading', loading: boolean): void
}>()
// 提交数据
const handleSubmit = async () => {
emit('loading', true)
try {
const result = await saveUser(form)
emit('ok', result) // 关闭弹窗并返回数据
} finally {
emit('loading', false)
}
}
// 取消
const handleCancel = () => {
emit('close')
}
</script>Drawer 抽屉
从屏幕边缘滑出的面板,适用于详情展示、表单编辑等场景。
pop.createDrawer
打开抽屉面板。
typescript
// 基础用法
const result = await pop.createDrawer(MyComponent, {
title: '详情',
width: 500
})
// 异步加载组件
const result = await pop.createDrawer(
import('./UserDetail.vue'),
{
title: '用户详情',
width: 600,
id: 'user-detail' // 防止重复打开
}
)
// 手动关闭
const drawer = pop.createDrawer(MyComponent)
drawer.close()pop.closeDrawer
根据 id 关闭抽屉。
typescript
pop.closeDrawer('user-detail')pop.hasDrawer
检查抽屉是否存在。
typescript
if (pop.hasDrawer('user-detail')) {
pop.closeDrawer('user-detail')
}DrawerConfig
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| title | string | - | 抽屉标题 |
| width | number | string | 'auto' | 抽屉宽度 |
| height | number | string | - | 抽屉高度(placement 为 top/bottom 时) |
| placement | string | 'right' | 抽屉位置:top/right/bottom/left |
| closable | boolean | true | 是否显示关闭按钮 |
| mask | boolean | true | 是否显示遮罩 |
| maskClosable | boolean | true | 点击遮罩是否关闭 |
| id | string | - | 唯一标识,用于防止重复打开 |
Page 页面
创建独立的页面组件,适用于全屏弹窗或复杂业务页面。
pop.createPage
创建独立的页面组件,适用于全屏弹窗或复杂页面。
typescript
// 基础用法
const result = await pop.createPage(MyPage, {
title: '新建订单',
bizType: 'create'
})
// 异步加载
const result = await pop.createPage(
import('./OrderPage.vue'),
{
id: 'order-page',
bizId: '123',
bizType: 'edit',
bizModel: { name: '订单1' }
}
)
// 手动关闭
const page = pop.createPage(MyPage)
page.close()PageConfig
| 参数 | 类型 | 说明 |
|---|---|---|
| id | string | 页面唯一标识 |
| title | string | 页面标题 |
| bizId | string | 业务 ID(编辑/查看时使用) |
| bizType | string | 业务类型(create/edit/view) |
| bizModel | object | 业务数据模型 |
| bizParams | object | 其他业务参数 |
| onOk | function | 确定回调 |
| onCancel | function | 取消回调 |
| onClose | function | 关闭回调 |
全局加载
显示全屏加载遮罩,阻止用户操作,适用于页面级别的加载状态。
pop.spin
显示全局加载遮罩。
typescript
// 显示加载
const spin = pop.spin()
// 处理完成后关闭
await doSomething()
spin.close()
// 自定义配置
const spin = pop.spin({
tip: '正在加载数据...',
size: 32
})SpinConfig
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| tip | string | '正在加载...' | 加载提示文字 |
| size | number | - | 加载图标大小 |
| dot | boolean | false | 是否使用点状加载 |
| hideIcon | boolean | false | 是否隐藏加载图标 |
路由集成
pop 服务支持与 Vue Router 集成,在路由切换时自动管理弹窗:
typescript
// main.ts
import { pop } from '@erp/biz'
import router from './router'
pop.install(app, router)
// 路由配置中添加 router_id
const routes = [
{
path: '/order',
component: OrderPage,
meta: {
router_id: 'order-page' // 用于弹窗关联
}
}
]pop.destroyByRouterId
销毁指定路由下的所有弹窗。
typescript
pop.destroyByRouterId('order-page')完整示例
列表页 CRUD
vue
<template>
<div>
<FkButton @click="handleCreate">新建</FkButton>
<FkTable :data="list">
<FkTableColumn label="操作">
<template #default="{ row }">
<FkButton @click="handleEdit(row)">编辑</FkButton>
<FkButton @click="handleDelete(row)">删除</FkButton>
</template>
</FkTableColumn>
</FkTable>
</div>
</template>
<script setup>
import { pop } from '@erp/biz'
// 新建
const handleCreate = async () => {
const result = await pop.createModal(
import('./EditForm.vue'),
{ type: 'create' },
{ title: '新建', width: 600 }
)
if (result) {
pop.success('创建成功')
refreshList()
}
}
// 编辑
const handleEdit = async (row) => {
const result = await pop.createDrawer(
import('./EditForm.vue'),
{
title: '编辑',
width: 500,
id: `edit-${row.id}`
}
)
if (result) {
pop.success('保存成功')
refreshList()
}
}
// 删除
const handleDelete = async (row) => {
try {
await pop.confirm(`确定删除 "${row.name}" 吗?`, {
title: '删除确认',
okButtonProps: { status: 'danger' }
})
const loading = pop.loading('正在删除...')
await deleteApi(row.id)
loading.close()
pop.success('删除成功')
refreshList()
} catch {
// 用户取消
}
}
</script>