Become a sponsor

说明
项目提供 BasicModal 组件(src/components/Modal/src/BasicModal.vue)和 useModal hook 管理弹窗状态。编辑弹窗通过 basicModal 组件实现,支持提交按钮 loading、标题动态设置等能力。
src/components/Modal/
├── src/
│ ├── BasicModal.vue # 主组件
│ ├── props.ts # 属性定义
│ ├── type.ts # 类型定义(ModalProps、ModalMethods)
│ └── hooks/
│ └── useModalContext.ts # 弹窗上下文
└── index.ts # 导出 useModal 等BasicModal 提供全屏切换、自定义头部、提交按钮等能力:
<basicModal
@register="modalRegister"
ref="modalRef"
class="basicModal basicFormModal"
@on-ok="handleSubmit"
@on-close="handleClose"
>
<template #default>
<!-- 表单内容 -->
</template>
</basicModal>核心功能:
setSubLoading)setProps 动态修改弹窗属性openModal / closeModal 控制显隐以岗位管理为例,使用 basicModal + useModal hook 管理弹窗:
<!-- src/views/system/position/index.vue -->
<script setup>
import editDialog from './edit.vue';
const createModalRef = ref();
const positionId = ref(0);
const editVisible = ref(false);
// 新增
const handleAdd = async () => {
positionId.value = 0;
editVisible.value = true;
await nextTick();
createModalRef.value.openModal();
};
// 编辑
async function handleEdit(record: Recordable) {
positionId.value = record.id;
editVisible.value = true;
await nextTick();
createModalRef.value.openModal();
}
</script>
<template>
<editDialog
ref="createModalRef"
:positionId="positionId"
v-if="editVisible"
v-model:visible="editVisible"
@success="reloadTable('noRefresh')"
/>
</template><!-- src/views/system/position/edit.vue -->
<template>
<basicModal
@register="modalRegister"
ref="modalRef"
class="basicModal basicFormModal"
@on-ok="handleSubmit"
@on-close="handleClose"
>
<template #default>
<n-form
class="ls-form"
ref="formRef"
:model="formData"
label-placement="left"
label-width="85px"
>
<n-form-item
label="岗位名称"
path="name"
:rule="{ required: true, message: '请输入岗位名称', trigger: 'blur' }"
>
<n-input v-model:value="formData.name" placeholder="请输入岗位名称" clearable />
</n-form-item>
<n-form-item label="岗位状态" path="code">
<n-radio-group v-model:value="formData.status" name="status">
<n-radio :value="1">正常</n-radio>
<n-radio :value="2">停用</n-radio>
</n-radio-group>
</n-form-item>
<n-form-item label="排序" path="sort">
<n-input-number v-model:value="formData.sort" />
</n-form-item>
</n-form>
</template>
</basicModal>
</template>
<script lang="ts" setup>
import { getPositionDetail, positionAdd, positionUpdate } from '@/api/system/position';
import { useMessage } from 'naive-ui';
import { useModal } from '@/components/Modal';
const emit = defineEmits(['success', 'update:visible']);
const formRef = ref();
const message = useMessage();
const formData = reactive({ id: '', name: '', status: 1, sort: 0 });
const props = defineProps({
visible: { type: Boolean, required: true, default: false },
positionId: { type: Number, required: true, default: 0 },
});
// 定义模态
const [modalRegister, { openModal, setSubLoading }] = useModal({
title: props.positionId ? '编辑岗位' : '添加岗位',
subBtuText: '确定',
width: 600,
});
// 提交处理
const handleSubmit = async () => {
formRef.value
.validate()
.then(async () => {
props.positionId ? await positionUpdate(formData) : await positionAdd(formData);
message.success('操作成功');
setSubLoading(false);
emit('update:visible', false);
emit('success');
})
.catch((error) => {
setSubLoading(false);
});
};
// 关闭弹窗
const handleClose = () => { emit('update:visible', false); };
// 编辑时加载数据
const setFormData = async () => {
const data = await getPositionDetail(props.positionId);
for (const key in formData) {
if (data[key] != null && data[key] != undefined) {
formData[key] = data[key];
}
}
};
onMounted(() => {
if (props.positionId) setFormData();
});
defineExpose({ openModal });
</script>父组件点击编辑 → positionId = record.id → editVisible = true → openModal()
↓
edit.vue onMounted → positionId != 0 → setFormData() → 获取详情填充表单
↓
用户修改 → handleSubmit → formRef.validate() → positionUpdate(formData)
↓
emit('success') → 父组件 reloadTable() → 表格刷新删除等危险操作使用 NaiveUI 的 useDialog:
import { useMessage, useDialog } from 'naive-ui';
const message = useMessage();
const dialog = useDialog();
async function handleDelete(record) {
dialog.warning({
title: '提示',
content: '确定要删除?',
positiveText: '确定',
negativeText: '取消',
onPositiveClick: async () => {
record.id ? await positionDelete(record.id) : await positionBatchDelete(rowKeys.value);
message.success('删除成功');
reloadTable();
},
});
}useDialog 返回 Dialog 实例,通过 dialog.warning() / dialog.error() 等方法弹出确认框,onPositiveClick 回调处理确认逻辑。
弹窗使用 v-model:visible 实现父子组件双向绑定:
<!-- 父组件 -->
<editDialog v-model:visible="editVisible" />
<!-- 子组件 -->
<script setup>
const emit = defineEmits(['update:visible']);
const handleClose = () => { emit('update:visible', false); };
</script>温馨提示
编辑弹窗使用 basicModal 组件,通过 useModal hook 管理弹窗状态(标题、宽度、提交按钮 loading)。setSubLoading(false) 在提交完成后关闭 loading。defineExpose({ openModal }) 暴露 openModal 方法供父组件调用。
编辑弹窗使用 basicModal + useModal hook 管理弹窗状态,通过 v-model:visible 双向绑定显隐状态,setSubLoading 控制提交按钮 loading 防重复提交。父组件通过 positionId prop 传递编辑行 ID,子组件在 onMounted 中判断并加载详情数据。操作成功后 emit('success') 通知父组件刷新表格。删除确认使用 NaiveUI 的 useDialog。