优化更新

This commit is contained in:
2026-09-14 09:44:33 +08:00
parent b3a9e21254
commit 5b8e178970
60 changed files with 1243 additions and 1022 deletions
@@ -1,7 +1,7 @@
# Modal 弹窗
:::tip 说明
项目提供 `BasicModal` 组件(`src/components/Modal/src/BasicModal.vue`)和原生 `el-dialog` 两种弹窗用法。编辑弹窗通过 `defineAsyncComponent` 懒加载,减少首屏渲染负担。
项目提供 `BasicModal` 组件(`src/components/Modal/src/BasicModal.vue`)和原生 `a-modal` 两种弹窗用法。编辑弹窗通过 `defineAsyncComponent` 懒加载,减少首屏渲染负担。
:::
## 组件架构
@@ -9,7 +9,7 @@
```
src/components/Modal/
├── src/
│ ├── BasicModal.vue # 主组件(基于 el-dialog)
│ ├── BasicModal.vue # 主组件(基于 a-modal)
│ ├── props.ts # 属性定义
│ ├── type.ts # 类型定义(ModalProps、ModalMethods)
│ └── hooks/
@@ -19,7 +19,7 @@ src/components/Modal/
## BasicModal 组件
`BasicModal` 基于 `el-dialog` 封装,提供全屏切换、自定义头部、提交按钮等能力:
`BasicModal` 基于 `a-modal` 封装,提供全屏切换、自定义头部、提交按钮等能力:
```vue
<BasicModal :title="'编辑'" :width="600" @register="registerModal" @ok="handleSubmit">
@@ -36,7 +36,7 @@ src/components/Modal/
## 实际用法(position 模块)
以岗位管理为例,实际使用原生 `el-dialog` + `defineAsyncComponent` 懒加载:
以岗位管理为例,实际使用原生 `a-modal` + `defineAsyncComponent` 懒加载:
### 父组件(index.vue)
@@ -57,8 +57,8 @@ const handleAdd = async () => {
};
// 编辑
const handleEdit = async (record: Recordable) => {
positionId.value = record.row.id;
const handleEdit = async (id: number) => {
positionId.value = id;
await nextTick();
editVisible.value = true;
};
@@ -81,41 +81,47 @@ const handleEdit = async (record: Recordable) => {
```vue
<!-- src/views/system/position/edit.vue -->
<template>
<el-dialog
v-model="props.visible"
<a-modal
v-model:visible="props.visible"
:title="props.positionId ? '编辑' : '新增'"
width="500"
:close-on-click-modal="false"
:before-close="dialogClose"
width="500px"
@cancel="dialogClose"
>
<el-form class="ls-form" ref="formRef" :model="formData" label-width="80px">
<el-form-item
<a-form
class="ls-form"
ref="formRef"
:model="formData"
:label-col="{ style: { width: '85px' } }"
>
<a-form-item
label="岗位名称"
prop="name"
name="name"
:rules="{ required: true, message: '请输入岗位名称', trigger: 'blur' }"
>
<el-input v-model="formData.name" placeholder="请输入岗位名称" clearable />
</el-form-item>
<el-form-item label="岗位状态" prop="status">
<el-radio-group v-model="formData.status">
<el-radio :value="1">正常</el-radio>
<el-radio :value="2">停用</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="排序" prop="sort">
<el-input-number v-model="formData.sort" />
</el-form-item>
</el-form>
<a-input v-model:value="formData.name" placeholder="请输入岗位名称" allow-clear />
</a-form-item>
<a-form-item label="岗位状态" name="status">
<a-radio-group v-model:value="formData.status">
<a-radio :value="1">正常</a-radio>
<a-radio :value="2">停用</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="排序" name="sort">
<a-input-number v-model:value="formData.sort" />
</a-form-item>
</a-form>
<template #footer>
<el-button @click="dialogClose">取消</el-button>
<el-button :loading="subLoading" type="primary" @click="submit">确定</el-button>
<a-button @click="dialogClose">取消</a-button>
<a-button :loading="subLoading" type="primary" @click="submit">确定</a-button>
</template>
</el-dialog>
</a-modal>
</template>
<script lang="ts" setup>
import type { FormInstance } from 'ant-design-vue';
import { getPositionDetail, positionAdd, positionUpdate } from '@/api/system/position';
import { useLockFn } from '@/utils/useLockFn';
import { message } from 'ant-design-vue';
const emit = defineEmits(['success', 'update:visible']);
const formRef = shallowRef<FormInstance>();
@@ -131,7 +137,7 @@ const props = defineProps({
const handleSubmit = async () => {
await formRef.value?.validate();
props.positionId ? await positionUpdate(formData) : await positionAdd(formData);
message('操作成功');
message.success('操作成功');
emit('update:visible', false);
emit('success');
};
@@ -161,7 +167,7 @@ onMounted(() => {
## 弹窗数据流
```
父组件点击编辑 → positionId = record.row.id → editVisible = true
父组件点击编辑 → positionId = id → editVisible = true
↓
edit.vue onMounted → positionId != 0 → setFormData() → 获取详情填充表单
↓
@@ -172,25 +178,25 @@ emit('success') → 父组件 reloadTable() → 表格刷新
## 确认弹窗
删除等危险操作使用 `confirm` 封装函数(来自 `src/utils/auth.ts`):
删除等危险操作使用 `Modal.confirm` 方法(来自 `ant-design-vue`):
```typescript
import { message, confirm } from '@/utils/auth';
import { Modal, message } from 'ant-design-vue';
async function handleDelete(record: Recordable) {
let ids = [];
if (!record) {
ids = selectionData.value.map(({ id }) => id);
}
await confirm('确定要删除?');
record ? await positionDelete(record.row.id) : await positionBatchDelete(ids);
message('删除成功');
reloadTable();
async function handleDelete(id?: number) {
Modal.confirm({
title: '提示',
content: '确定要删除?',
onOk: async () => {
id ? await positionDelete(id) : await positionBatchDelete(selectionData.value);
message.success('删除成功');
reloadTable();
},
});
}
```
`confirm` 内部调用 `ElMessageBox.confirm`,返回 Promise,用户取消时抛出异常中断后续逻辑。
`Modal.confirm` 返回 Promise,用户取消时不会执行 `onOk` 回调。
## v-model:visible 双向绑定
@@ -213,4 +219,4 @@ const dialogClose = () => { emit('update:visible', false); };
## 总结
编辑弹窗使用 `el-dialog` + `defineAsyncComponent` 懒加载,通过 `v-model:visible` 双向绑定显隐状态,`useLockFn` 防重复提交。父组件通过 `positionId` prop 传递编辑行 ID,子组件在 `onMounted` 中判断并加载详情数据。操作成功后 `emit('success')` 通知父组件刷新表格。
编辑弹窗使用 `a-modal` + `defineAsyncComponent` 懒加载,通过 `v-model:visible` 双向绑定显隐状态,`useLockFn` 防重复提交。父组件通过 `positionId` prop 传递编辑行 ID,子组件在 `onMounted` 中判断并加载详情数据。操作成功后 `emit('success')` 通知父组件刷新表格。