全局配置修改
parent
2e712817a1
commit
120a17f55a
|
|
@ -0,0 +1,86 @@
|
||||||
|
/**
|
||||||
|
* 批量修复所有对话框,添加 :close-on-click-modal="false" 属性
|
||||||
|
* 运行方法: node fix_dialogs.js
|
||||||
|
*/
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
// 需要处理的目录
|
||||||
|
const directories = [
|
||||||
|
'ruoyi-fastapi-frontend/src/views',
|
||||||
|
'ruoyi-fastapi-frontend/src/components'
|
||||||
|
];
|
||||||
|
|
||||||
|
// 递归读取目录中的所有.vue文件
|
||||||
|
function getAllVueFiles(dir, fileList = []) {
|
||||||
|
const files = fs.readdirSync(dir);
|
||||||
|
|
||||||
|
files.forEach(file => {
|
||||||
|
const filePath = path.join(dir, file);
|
||||||
|
const stat = fs.statSync(filePath);
|
||||||
|
|
||||||
|
if (stat.isDirectory()) {
|
||||||
|
getAllVueFiles(filePath, fileList);
|
||||||
|
} else if (file.endsWith('.vue')) {
|
||||||
|
fileList.push(filePath);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return fileList;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修复单个文件
|
||||||
|
function fixDialogInFile(filePath) {
|
||||||
|
let content = fs.readFileSync(filePath, 'utf8');
|
||||||
|
let modified = false;
|
||||||
|
|
||||||
|
// 匹配所有的 <el-dialog 标签,但不包含已经有 close-on-click-modal 属性的
|
||||||
|
const dialogRegex = /<el-dialog\s+([^>]*?)>/g;
|
||||||
|
|
||||||
|
content = content.replace(dialogRegex, (match, attributes) => {
|
||||||
|
// 检查是否已经有 close-on-click-modal 属性
|
||||||
|
if (attributes.includes('close-on-click-modal')) {
|
||||||
|
return match; // 已经有了,不修改
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加属性
|
||||||
|
modified = true;
|
||||||
|
return `<el-dialog ${attributes} :close-on-click-modal="false">`;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (modified) {
|
||||||
|
fs.writeFileSync(filePath, content, 'utf8');
|
||||||
|
console.log(`✓ 已修复: ${filePath}`);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 主函数
|
||||||
|
function main() {
|
||||||
|
console.log('开始批量修复对话框...\n');
|
||||||
|
|
||||||
|
let totalFiles = 0;
|
||||||
|
let modifiedFiles = 0;
|
||||||
|
|
||||||
|
directories.forEach(dir => {
|
||||||
|
if (fs.existsSync(dir)) {
|
||||||
|
const vueFiles = getAllVueFiles(dir);
|
||||||
|
totalFiles += vueFiles.length;
|
||||||
|
|
||||||
|
vueFiles.forEach(file => {
|
||||||
|
if (fixDialogInFile(file)) {
|
||||||
|
modifiedFiles++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`\n完成!`);
|
||||||
|
console.log(`总共检查了 ${totalFiles} 个文件`);
|
||||||
|
console.log(`修改了 ${modifiedFiles} 个文件`);
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
v-bind="$attrs"
|
||||||
|
v-on="$listeners"
|
||||||
|
:close-on-click-modal="closeOnClickModal"
|
||||||
|
>
|
||||||
|
<slot></slot>
|
||||||
|
<template v-for="(_, name) in $slots" v-slot:[name]>
|
||||||
|
<slot :name="name"></slot>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'Dialog',
|
||||||
|
inheritAttrs: false,
|
||||||
|
props: {
|
||||||
|
closeOnClickModal: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false // 默认不允许点击遮罩层关闭
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
/**
|
||||||
|
* 全局禁用对话框点击遮罩层关闭的指令
|
||||||
|
* 使用方法: <el-dialog v-disable-modal-close ...>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
bind(el, binding, vnode) {
|
||||||
|
// 等待DOM渲染完成
|
||||||
|
setTimeout(() => {
|
||||||
|
// 找到遮罩层元素
|
||||||
|
const modalElement = el.querySelector('.el-dialog__wrapper') || el.parentElement
|
||||||
|
if (modalElement) {
|
||||||
|
// 移除点击事件监听器
|
||||||
|
modalElement.onclick = function(e) {
|
||||||
|
// 如果点击的是遮罩层本身(不是对话框内容),阻止默认行为
|
||||||
|
if (e.target.classList.contains('el-dialog__wrapper')) {
|
||||||
|
e.stopPropagation()
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 100)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -78,16 +78,14 @@ Vue.use(Element, {
|
||||||
|
|
||||||
// 全局设置 el-dialog 默认不允许点击遮罩层关闭
|
// 全局设置 el-dialog 默认不允许点击遮罩层关闭
|
||||||
// 解决所有对话框点击外部区域会关闭的问题
|
// 解决所有对话框点击外部区域会关闭的问题
|
||||||
Vue.component('el-dialog', {
|
// 必须在 Vue.use(Element) 之后执行
|
||||||
...Element.Dialog,
|
const DialogConstructor = Vue.component('ElDialog')
|
||||||
props: {
|
if (DialogConstructor && DialogConstructor.options && DialogConstructor.options.props) {
|
||||||
...Element.Dialog.props,
|
const closeOnClickModalProp = DialogConstructor.options.props.closeOnClickModal
|
||||||
closeOnClickModal: {
|
if (closeOnClickModalProp) {
|
||||||
type: Boolean,
|
closeOnClickModalProp.default = false
|
||||||
default: false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
Vue.config.productionTip = false
|
Vue.config.productionTip = false
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -125,7 +125,7 @@
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- 添加或修改入库单对话框 -->
|
<!-- 添加或修改入库单对话框 -->
|
||||||
<el-dialog :title="title" :visible.sync="open" width="1200px" append-to-body>
|
<el-dialog :title="title" :visible.sync="open" width="1200px" append-to-body :close-on-click-modal="false">
|
||||||
<el-form ref="form" :model="form" :rules="rules" label-width="120px">
|
<el-form ref="form" :model="form" :rules="rules" label-width="120px">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,7 @@
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- 添加或修改样品对话框 -->
|
<!-- 添加或修改样品对话框 -->
|
||||||
<el-dialog :title="title" :visible.sync="open" width="700px" append-to-body>
|
<el-dialog :title="title" :visible.sync="open" width="700px" append-to-body :close-on-click-modal="false">
|
||||||
<el-form ref="form" :model="form" :rules="rules" label-width="140px">
|
<el-form ref="form" :model="form" :rules="rules" label-width="140px">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
|
|
|
||||||
|
|
@ -10,78 +10,191 @@ Element UI 的 `el-dialog` 组件有一个属性 `close-on-click-modal`,其默
|
||||||
|
|
||||||
## 解决方案
|
## 解决方案
|
||||||
|
|
||||||
### 方案选择
|
### 方案1:全局配置(推荐但可能需要重启)
|
||||||
|
|
||||||
考虑到项目中有大量的对话框(超过20个),如果逐个修改每个对话框添加 `:close-on-click-modal="false"` 属性,工作量大且容易遗漏。因此采用**全局配置方案**。
|
|
||||||
|
|
||||||
### 实施步骤
|
|
||||||
|
|
||||||
在 `src/main.js` 文件中,添加全局配置来覆盖 Element UI Dialog 组件的默认行为:
|
在 `src/main.js` 文件中,添加全局配置来覆盖 Element UI Dialog 组件的默认行为:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// 全局设置 el-dialog 默认不允许点击遮罩层关闭
|
// 全局设置 el-dialog 默认不允许点击遮罩层关闭
|
||||||
// 解决所有对话框点击外部区域会关闭的问题
|
// 解决所有对话框点击外部区域会关闭的问题
|
||||||
Vue.component('el-dialog', {
|
// 必须在 Vue.use(Element) 之后执行
|
||||||
...Element.Dialog,
|
const DialogConstructor = Vue.component('ElDialog')
|
||||||
props: {
|
if (DialogConstructor && DialogConstructor.options && DialogConstructor.options.props) {
|
||||||
...Element.Dialog.props,
|
const closeOnClickModalProp = DialogConstructor.options.props.closeOnClickModal
|
||||||
closeOnClickModal: {
|
if (closeOnClickModalProp) {
|
||||||
type: Boolean,
|
closeOnClickModalProp.default = false
|
||||||
default: false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 修改文件
|
**注意**:此方法需要完全重启前端服务(不是热重载),并清除浏览器缓存。
|
||||||
|
|
||||||
- `ruoyi-fastapi-frontend/src/main.js`
|
### 方案2:逐个添加属性(最可靠)
|
||||||
|
|
||||||
### 影响范围
|
在每个对话框标签上添加 `:close-on-click-modal="false"` 属性:
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<!-- 修改前 -->
|
||||||
|
<el-dialog :title="title" :visible.sync="open" width="1200px" append-to-body>
|
||||||
|
|
||||||
|
<!-- 修改后 -->
|
||||||
|
<el-dialog :title="title" :visible.sync="open" width="1200px" append-to-body :close-on-click-modal="false">
|
||||||
|
```
|
||||||
|
|
||||||
|
### 方案3:使用批量修复脚本
|
||||||
|
|
||||||
|
运行提供的 `fix_dialogs.js` 脚本来批量修改所有对话框:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node fix_dialogs.js
|
||||||
|
```
|
||||||
|
|
||||||
|
## 实施步骤
|
||||||
|
|
||||||
|
### 步骤1:修改main.js(已完成)
|
||||||
|
|
||||||
|
文件:`ruoyi-fastapi-frontend/src/main.js`
|
||||||
|
|
||||||
|
### 步骤2:修改主要对话框(已完成)
|
||||||
|
|
||||||
|
已修改的文件:
|
||||||
|
- `ruoyi-fastapi-frontend/src/views/warehouse/receipt/index.vue` - 入库单对话框
|
||||||
|
- `ruoyi-fastapi-frontend/src/views/warehouse/sample/index.vue` - 样品对话框
|
||||||
|
|
||||||
|
### 步骤3:重启前端服务
|
||||||
|
|
||||||
|
**重要**:必须完全停止并重新启动前端服务,热重载可能不会生效。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 停止当前服务 (Ctrl+C)
|
||||||
|
# 然后重新启动
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
### 步骤4:清除浏览器缓存
|
||||||
|
|
||||||
|
1. 打开浏览器开发者工具(F12)
|
||||||
|
2. 右键点击刷新按钮
|
||||||
|
3. 选择"清空缓存并硬性重新加载"
|
||||||
|
|
||||||
|
或者使用快捷键:
|
||||||
|
- Chrome/Edge: `Ctrl + Shift + Delete`
|
||||||
|
- Firefox: `Ctrl + Shift + Delete`
|
||||||
|
|
||||||
|
### 步骤5:批量修改其他对话框(可选)
|
||||||
|
|
||||||
|
如果全局配置不生效,运行批量修复脚本:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node fix_dialogs.js
|
||||||
|
```
|
||||||
|
|
||||||
|
这将自动为所有对话框添加 `:close-on-click-modal="false"` 属性。
|
||||||
|
|
||||||
|
## 影响范围
|
||||||
|
|
||||||
此修改会影响整个项目中所有使用 `el-dialog` 的对话框,包括但不限于:
|
此修改会影响整个项目中所有使用 `el-dialog` 的对话框,包括但不限于:
|
||||||
|
|
||||||
- 入库单管理对话框
|
- ✅ 入库单管理对话框(已手动修改)
|
||||||
- 样品管理对话框
|
- ✅ 样品管理对话框(已手动修改)
|
||||||
- 用户管理对话框
|
- 用户管理对话框
|
||||||
- 角色管理对话框
|
- 角色管理对话框
|
||||||
- 菜单管理对话框
|
- 菜单管理对话框
|
||||||
- 测试工单对话框
|
- 测试工单对话框
|
||||||
- 测试流程对话框
|
- 测试流程对话框
|
||||||
- 等等...
|
- 等等...(共20+个对话框)
|
||||||
|
|
||||||
### 优点
|
## 验证方法
|
||||||
|
|
||||||
1. **一次修改,全局生效**:只需修改一个文件,所有对话框都会应用新的默认行为
|
|
||||||
2. **维护简单**:未来新增的对话框也会自动继承这个配置
|
|
||||||
3. **用户体验提升**:避免用户误操作导致数据丢失
|
|
||||||
4. **代码简洁**:不需要在每个对话框上重复添加相同的属性
|
|
||||||
|
|
||||||
### 特殊情况处理
|
|
||||||
|
|
||||||
如果某些对话框确实需要点击外部关闭的功能,可以在该对话框上显式设置:
|
|
||||||
|
|
||||||
```vue
|
|
||||||
<el-dialog :close-on-click-modal="true" ...>
|
|
||||||
<!-- 对话框内容 -->
|
|
||||||
</el-dialog>
|
|
||||||
```
|
|
||||||
|
|
||||||
## 测试验证
|
|
||||||
|
|
||||||
修改后,请测试以下场景:
|
修改后,请测试以下场景:
|
||||||
|
|
||||||
1. ✅ 打开任意对话框,点击对话框外部区域,对话框不应关闭
|
1. ✅ 打开任意对话框,点击对话框外部区域,对话框**不应关闭**
|
||||||
2. ✅ 点击对话框右上角的关闭按钮(X),对话框应正常关闭
|
2. ✅ 点击对话框右上角的关闭按钮(X),对话框应正常关闭
|
||||||
3. ✅ 点击对话框底部的"取消"按钮,对话框应正常关闭
|
3. ✅ 点击对话框底部的"取消"按钮,对话框应正常关闭
|
||||||
4. ✅ 点击对话框底部的"确定"按钮,对话框应正常关闭并提交数据
|
4. ✅ 点击对话框底部的"确定"按钮,对话框应正常关闭并提交数据
|
||||||
5. ✅ 按 ESC 键,对话框应正常关闭(如果需要禁用此功能,可设置 `:close-on-press-escape="false"`)
|
5. ✅ 按 ESC 键,对话框应正常关闭(如果需要禁用此功能,可设置 `:close-on-press-escape="false"`)
|
||||||
|
|
||||||
|
## 故障排查
|
||||||
|
|
||||||
|
### 问题:修改后对话框仍然可以点击外部关闭
|
||||||
|
|
||||||
|
**可能原因1**:前端服务没有完全重启
|
||||||
|
- **解决方法**:完全停止服务(Ctrl+C),然后重新运行 `npm run dev`
|
||||||
|
|
||||||
|
**可能原因2**:浏览器缓存
|
||||||
|
- **解决方法**:清除浏览器缓存并硬性重新加载(Ctrl+Shift+R)
|
||||||
|
|
||||||
|
**可能原因3**:全局配置未生效
|
||||||
|
- **解决方法**:使用方案2或方案3,直接在对话框标签上添加属性
|
||||||
|
|
||||||
|
**可能原因4**:某些对话框使用了显式的 `:close-on-click-modal="true"`
|
||||||
|
- **解决方法**:搜索并修改这些特殊情况
|
||||||
|
|
||||||
|
### 问题:如何验证全局配置是否生效
|
||||||
|
|
||||||
|
在浏览器控制台中运行:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 检查Dialog组件的默认props
|
||||||
|
const DialogConstructor = Vue.component('ElDialog')
|
||||||
|
console.log(DialogConstructor.options.props.closeOnClickModal.default)
|
||||||
|
// 应该输出: false
|
||||||
|
```
|
||||||
|
|
||||||
|
## 备用方案
|
||||||
|
|
||||||
|
如果以上方法都不生效,可以使用以下临时方案:
|
||||||
|
|
||||||
|
### 方案A:使用CSS禁用遮罩层点击
|
||||||
|
|
||||||
|
在 `src/assets/styles/index.scss` 中添加:
|
||||||
|
|
||||||
|
```scss
|
||||||
|
// 禁用对话框遮罩层的点击事件
|
||||||
|
.el-dialog__wrapper {
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
.el-dialog {
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 方案B:使用全局事件监听
|
||||||
|
|
||||||
|
在 `src/main.js` 中添加:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 全局拦截对话框关闭事件
|
||||||
|
Vue.prototype.$msgbox = function(options) {
|
||||||
|
return MessageBox({
|
||||||
|
...options,
|
||||||
|
closeOnClickModal: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## 日期
|
## 日期
|
||||||
|
|
||||||
修复日期:2025-12-05
|
- 初次修复:2025-12-05
|
||||||
|
- 更新方案:2025-12-05
|
||||||
|
|
||||||
## 相关问题
|
## 相关问题
|
||||||
|
|
||||||
- 入库单详情查看错误(已同时修复)
|
- 入库单详情查看错误(已同时修复)
|
||||||
- 数据模型字段缺失问题(已同时修复)
|
- 数据模型字段缺失问题(已同时修复)
|
||||||
|
|
||||||
|
## 附加工具
|
||||||
|
|
||||||
|
### 批量修复脚本使用说明
|
||||||
|
|
||||||
|
`fix_dialogs.js` 脚本会:
|
||||||
|
1. 扫描 `src/views` 和 `src/components` 目录下的所有 `.vue` 文件
|
||||||
|
2. 查找所有 `<el-dialog>` 标签
|
||||||
|
3. 为没有 `close-on-click-modal` 属性的对话框自动添加 `:close-on-click-modal="false"`
|
||||||
|
4. 输出修改的文件列表
|
||||||
|
|
||||||
|
运行前请确保:
|
||||||
|
- 已安装 Node.js
|
||||||
|
- 在项目根目录下运行
|
||||||
|
- 建议先备份代码或使用Git版本控制
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue