案例背景
流程审批时,需要查看另一个页面的内容而不离开当前页面;想要查看另一个页面详情的同时保留当前页面状态。实现更好的用户体验,避免频繁跳转页面
这里以一个模拟案例分步说明实现方案及演示。
实现方案说明
1、在页面上新增一个浏览按钮,可参考【泛微OA Ecology 9.0】通过JavaScript 流程表单创建自定义按钮_泛微自定义按钮-优快云博客
2、创建模态框容器&CSS样式
3、JS创建模态框相关调用函数
4、绑定按钮点击事件(按实际需求设定)
详细实现步骤
创建模态框容器
// 创建模态框结构
var modal = $(`
<div id="performanceModal" class="performance-modal">
<div class="modal-container">
<div class="modal-header">
<h3>明细数据</h3>
<button class="close-btn">×</button>
</div>
<div class="modal-body">
<iframe id="performanceFrame"></iframe>
</div>
<div class="modal-footer">
<button class="new-window-btn">
<svg width="14" height="14" viewBox="0 0 24 24">
<path d="M19 19H5V5h7V3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"/>
</svg>
在新窗口打开
</button>
</div>
</div>
</div>
`);
// 将模态框添加到页面 ===
$("body").append(modal);
构建模态框CSS样式
以下可参考,实际按需进行调整
<style>
/* === 1. 模态框基础样式 === */
.performance-modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.6); /* 半透明黑色背景 */
z-index: 9999; /* 确保在最上层 */
display: none; /* 默认隐藏 */
align-items: center;
justify-content: center;
opacity: 0;
transition: opacity 0.3s ease; /* 淡入动画 */
}
/* 激活状态的模态框 */
.performance-modal.active {
display: flex;
opacity: 1;
}
/* === 2. 模态框容器 === */
.modal-container {
background: white;
border-radius: 8px;
width: 80%;
height: 80%;
max-width: none;
max-height: none;
display: flex;
flex-direction: column; /* 垂直布局 */
box-shadow: 0 5px 15px rgba(0,0,0,0.3); /* 阴影效果 */
transform: translateY(-20px); /* 初始位置偏上 */
transition: transform 0.3s ease; /* 下落动画 */
}
/* 激活状态的容器 */
.performance-modal.active .modal-container {
transform: translateY(0); /* 回到正常位置 */
}
/* === 3. 模态框头部 === */
.modal-header {
padding: 16px 20px;
border-bottom: 1px solid #eee; /* 底部边框 */
display: flex;
justify-content: space-between;
align-items: center;
}
.modal-header h3 {
margin: 0;
font-size: 18px;
color: #333;
}
/* 关闭按钮样式 */
.close-btn {
background: none;
border: none;
font-size: 24px;
cursor: pointer;
color: #666;
padding: 0 8px;
}
/* === 4. 模态框主体 === */
.modal-body {
flex: 1; /* 占据剩余空间 */
min-height: 600px;
overflow: hidden;
padding: 0;
}
/* iframe样式 */
#performanceFrame {
width: 100%;
height: 100%;
border: none;
display: block;
}
/* === 5. 模态框底部 === */
.modal-footer {
padding: 12px 20px;
border-top: 1px solid #eee; /* 顶部边框 */
text-align: right;
}
/* 新窗口打开按钮 */
.new-window-btn {
background: none;
border: none;
color: #1890ff; /* 主题蓝色 */
cursor: pointer;
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 14px;
padding: 5px 10px;
border-radius: 4px;
}
/* 鼠标悬停效果 */
.new-window-btn:hover {
background: #f0faff; /* 浅蓝色背景 */
}
/* === 6. 加载动画 === */
.loading-spinner {
display: inline-block;
width: 12px;
height: 12px;
border: 2px solid rgba(0,0,0,0.2);
border-radius: 50%;
border-top-color: #000; /* 顶部边框颜色不同,形成旋转效果 */
animation: spin 1s linear infinite; /* 无限旋转动画 */
margin-right: 8px;
}
/* 旋转动画定义 */
@keyframes spin {
to { transform: rotate(360deg); }
}
</style>
模态框调用相关函数
// === 1. 显示模态框函数 ===
function showModal(url) {
const $modal = $('#performanceModal');
const $iframe = $('#performanceFrame');
// 先清空iframe再重新加载,避免缓存问题
$iframe.attr('src', 'about:blank');
setTimeout(() => {
$iframe.attr('src', url);
$modal.addClass('active');
}, 100);
}
// === 2. 关闭模态框事件 ===
$(document).on('click', '#performanceModal .close-btn, #performanceModal', function (e) {
// 点击关闭按钮或模态框外部时关闭
if ($(e.target).closest('.modal-container').length === 0 || $(e.target).hasClass('close-btn')) {
$('#performanceModal').removeClass('active');
$('#performanceFrame').attr('src', 'about:blank');
}
});
// === 3. ESC键关闭模态框 ===
$(document).keyup(function (e) {
if (e.key === "Escape") {
$('#performanceModal').removeClass('active');
}
});
完整代码
案例说明:
点击页面上【查看明细数据】按钮,根据表单上"field111"和"field222"两个字段的值,请求后端接口获取对应明细数据的"id"。
将获取到的"id"与模块卡片页面的URL进行拼接,生成一个完整的跳转URL并进行跳转。
JavaScript实现
'use strict';
// 使用初始化标志确保只执行一次
if (!window.performanceModalInitialized) {
window.performanceModalInitialized = true;
jQuery(document).ready(function ($) {
// === 1. 创建UI元素 ===
// 创建 查看明细数据 按钮
var button = $(`
<button id="performanceBtn"
title="查看明细数据"
type="button"
class="ant-btn ant-btn-primary">
查看明细数据
</button>
`);
// 创建模态框结构
var modal = $(`
<div id="performanceModal" class="performance-modal">
<div class="modal-container">
<div class="modal-header">
<h3>明细数据</h3>
<button class="close-btn">×</button>
</div>
<div class="modal-body">
<iframe id="performanceFrame"></iframe>
</div>
<div class="modal-footer">
<button class="new-window-btn">
<svg width="14" height="14" viewBox="0 0 24 24">
<path d="M19 19H5V5h7V3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"/>
</svg>
在新窗口打开
</button>
</div>
</div>
</div>
`);
// === 2. 将元素添加到页面 ===
$("#ckmx").append(button); // 添加按钮到表单'ckmx'位置
$("body").append(modal);
// === 3. 绑定按钮点击事件 ===
button.on("click", async function () {
// 保存原始按钮内容,用于恢复
var originalHtml = button.html();
// 显示加载状态
button.prop('disabled', true)
.html('<span class="loading-spinner"></span> 加载中...');
try {
// 3.1 获取明细数据ID
const performanceId = await fetchPerformanceData();
// 3.2 构建详情页URL
const targetUrl = buildPerformanceUrl(performanceId);
// 3.3 显示模态框
showModal(targetUrl);
// 3.4 绑定新窗口打开按钮事件
$('.new-window-btn').off('click').on('click', function () {
window.open(targetUrl, '_blank');
});
} catch (error) {
// 错误处理
console.error("操作失败:", error);
alert("获取明细数据失败: " + error.message);
} finally {
// 恢复按钮状态
button.prop('disabled', false).html(originalHtml);
}
});
// === 4. 关闭模态框事件 ===
$(document).on('click', '#performanceModal .close-btn, #performanceModal', function (e) {
// 点击关闭按钮或模态框外部时关闭
if ($(e.target).closest('.modal-container').length === 0 || $(e.target).hasClass('close-btn')) {
$('#performanceModal').removeClass('active');
$('#performanceFrame').attr('src', 'about:blank');
}
});
// === 5. ESC键关闭模态框 ===
$(document).keyup(function (e) {
if (e.key === "Escape") {
$('#performanceModal').removeClass('active');
}
});
// === 6. 数据获取函数 ===
async function fetchPerformanceData() {
// 6.1 获取表单数据
const param1 = WfForm.getFieldValue("field111"); // 获取必填字段1
const param2 = WfForm.getFieldValue("field222"); // 获取必填字段2
// 6.2 验证必填字段
if (!param1 || !param2) throw new Error("请填写完整信息");
// 6.3 请求明细数据
const result = await $.ajax({
type: "POST",
url: "/api/performance/getPrevious", // 以实际接口链接为准,请替换为实际URL
data: {
param1, param2
},
dataType: "json"
});
// 6.4 验证返回结果
if (!result?.[0]?.id) throw new Error("未获取到明细数据");
return result[0].id;
}
// === 7. URL构建函数 ===
function buildPerformanceUrl(id) {
return `/spa/cube/index.html#/main/cube/card?type=0&modeId=49&formId=-113&opentype=0&customid=59&billid=${id}`; //以实际链接为准,请替换为实际URL
}
// === 8. 显示模态框函数 ===
function showModal(url) {
const $modal = $('#performanceModal');
const $iframe = $('#performanceFrame');
// 先清空iframe再重新加载,避免缓存问题
$iframe.attr('src', 'about:blank');
setTimeout(() => {
$iframe.attr('src', url);
$modal.addClass('active');
}, 100);
}
});
}
CSS样式
<style>
/* === 1. 模态框基础样式 === */
.performance-modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.6); /* 半透明黑色背景 */
z-index: 9999; /* 确保在最上层 */
display: none; /* 默认隐藏 */
align-items: center;
justify-content: center;
opacity: 0;
transition: opacity 0.3s ease; /* 淡入动画 */
}
/* 激活状态的模态框 */
.performance-modal.active {
display: flex;
opacity: 1;
}
/* === 2. 模态框容器 === */
.modal-container {
background: white;
border-radius: 8px;
width: 80%;
height: 80%;
max-width: none;
max-height: none;
display: flex;
flex-direction: column; /* 垂直布局 */
box-shadow: 0 5px 15px rgba(0,0,0,0.3); /* 阴影效果 */
transform: translateY(-20px); /* 初始位置偏上 */
transition: transform 0.3s ease; /* 下落动画 */
}
/* 激活状态的容器 */
.performance-modal.active .modal-container {
transform: translateY(0); /* 回到正常位置 */
}
/* === 3. 模态框头部 === */
.modal-header {
padding: 16px 20px;
border-bottom: 1px solid #eee; /* 底部边框 */
display: flex;
justify-content: space-between;
align-items: center;
}
.modal-header h3 {
margin: 0;
font-size: 18px;
color: #333;
}
/* 关闭按钮样式 */
.close-btn {
background: none;
border: none;
font-size: 24px;
cursor: pointer;
color: #666;
padding: 0 8px;
}
/* === 4. 模态框主体 === */
.modal-body {
flex: 1; /* 占据剩余空间 */
min-height: 600px;
overflow: hidden;
padding: 0;
}
/* iframe样式 */
#performanceFrame {
width: 100%;
height: 100%;
border: none;
display: block;
}
/* === 5. 模态框底部 === */
.modal-footer {
padding: 12px 20px;
border-top: 1px solid #eee; /* 顶部边框 */
text-align: right;
}
/* 新窗口打开按钮 */
.new-window-btn {
background: none;
border: none;
color: #1890ff; /* 主题蓝色 */
cursor: pointer;
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 14px;
padding: 5px 10px;
border-radius: 4px;
}
/* 鼠标悬停效果 */
.new-window-btn:hover {
background: #f0faff; /* 浅蓝色背景 */
}
/* === 6. 加载动画 === */
.loading-spinner {
display: inline-block;
width: 12px;
height: 12px;
border: 2px solid rgba(0,0,0,0.2);
border-radius: 50%;
border-top-color: #000; /* 顶部边框颜色不同,形成旋转效果 */
animation: spin 1s linear infinite; /* 无限旋转动画 */
margin-right: 8px;
}
/* 旋转动画定义 */
@keyframes spin {
to { transform: rotate(360deg); }
}
</style>
关键点说明
-
初始化控制:使用
window.performanceModalInitialized确保脚本只执行一次 -
UI构建:
-
动态创建按钮和模态框元素
-
模态框包含header、body和footer三部分
-
body部分使用iframe加载外部内容
-
-
数据获取:
-
从表单获取查询信息
-
通过AJAX请求获取建模表单的数据ID
-
-
交互逻辑:
-
按钮点击时显示加载状态
-
成功获取数据后显示模态框
-
支持新窗口打开
-
多种关闭方式(按钮、点击外部、ESC键)
-
-
动画效果:
-
模态框淡入淡出
-
内容区域下落动画
-
加载旋转动画
-
-
错误处理:
-
表单验证
-
数据获取验证
-
友好的错误提示
-

4274

被折叠的 条评论
为什么被折叠?



