> 适用于 Java(Spring Boot)后端接口,请求方式为 $iget / $ipost。
项目静态资源位于 static/phm/ 下,每个功能模块对应 html/ 和 scripts/ 两个目录,每页两个文件(HTML + JS):
static/phm/
├── base/ # 基础配置模块
│ ├── html/ # HTML 页面文件
│ │ ├── dict.html # 字典配置页面
│ │ ├── route.html # 路由配置页面
│ │ └── auth.assign.html
│ └── scripts/ # 对应 JS 逻辑文件
│ ├── dict.js
│ ├── route.js
│ └── auth.assign.js
├── common/ # 公共库(所有模块共用)
│ ├── scripts/
│ │ ├── com.hisui.phm.js # HISUI 公共方法(必须引入)
│ │ ├── com.sys.js # 系统公共方法(必须引入)
│ │ ├── com.fun.js # 通用工具方法(必须引入)
│ │ ├── component.js # 组件初始化
│ │ ├── phm.auth.js # 权限控制(按钮显示/隐藏)
│ ├── scripts_lib/ # 第三方库(如 SheetJS)│
│ └── css/
│ └── base.css # 公共样式
命名规则:
dict.html ↔ dict.js)../../common/scripts/xxx.js 引用<!-- FileName: static/phm/模块名/html/xxx.html -->
<!-- Author: 作者名 -->
<!-- Date: 创建日期 -->
<!-- Description: 页面描述 -->
<!DOCTYPE html>
<html lang="en">
<meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>页面标题</title>
<!-- 【必须】引入公共 hisui(顺序不可变) -->
<script type="text/javascript" src="../../common/scripts/com.hisui.phm.js"></script>
<script type="text/javascript" src="../../common/scripts/com.sys.js"></script>
<script type="text/javascript" src="../../common/scripts/com.fun.js"></script>
<!-- 引用公共 css、js -->
<link href="../../common/css/base.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="../../common/scripts/component.js"></script>
<!-- 引用业务 js(与 HTML 同名,放在 head 前) -->
<script src="../scripts/xxx.js" type="text/javascript"></script>
<!-- 控制组件显示隐藏(权限:根据后台配置自动禁用/启用按钮) -->
<script src="../../common/scripts/phm.auth.js" type="text/javascript"></script>
<!-- 如需 SheetJS 等第三方库,按需引入 -->
<!-- <script type="text/javascript" src="../../common/scripts_lib/SheetJS/xlsx.full.min.js"></script> -->
<head></head>
<body>
<!-- 主页面 - 使用 hisui-layout 五方布局 -->
<div class="hisui-layout" data-options="fit:true">
<div data-options="region:'north',border:false" style="height:50px;padding:10px;">
<!-- 顶部:查询条件 -->
<table class="search-table">
<tr>
<td class="r-label"><label for="txtName" class="hisui-label">名称</label></td>
<td><input class="hisui-textbox" id="txtName" style="width:150px"></td>
<td class="search-btnlist">
<a id="btnQuery" class="hisui-linkbutton" data-options="iconCls:'icon-w-find'">查询</a>
</td>
</tr>
</table>
</div>
<div data-options="region:'center',border:false" style="padding:10px;">
<!-- 中央:主数据表格 -->
<table id="gridMain" data-options="toolbar:'#ToolBar'"></table>
<div id="ToolBar" style="padding:3px;">
<a class="hisui-linkbutton" id="btnAdd"
data-options="iconCls:'icon-add',plain:true">新增</a>
<a class="hisui-linkbutton" id="btnEdit"
data-options="iconCls:'icon-write-order',plain:true,disabled:true">修改</a>
<a class="hisui-linkbutton" id="btnDelete"
data-options="iconCls:'icon-cancel',plain:true,disabled:true">删除</a>
</div>
</div>
</div>
<!-- 编辑对话框(内容直接写在 HTML 中,data-options="closed:true" 初始隐藏) -->
<div id="winEdit" class="hisui-dialog" data-options="closed:true" style="padding:10px 10px 0px 10px;">
<table class="search-table">
<tr>
<td class="r-label"><label for="txtCode" class="hisui-label">代码</label></td>
<td><input class="textbox" id="txtCode" style="width:260px" type="text"/></td>
</tr>
<tr>
<td class="r-label"><label for="txtDesc" class="hisui-label">描述</label></td>
<td><input class="textbox" id="txtDesc" style="width:260px" type="text"/></td>
</tr>
<tr>
<td class="r-label"><label for="chkIsActive" class="hisui-label">是否有效</label></td>
<td><input type='hisui-checkbox' type="checkbox" id="chkIsActive"/></td>
</tr>
<tr>
<td colspan="2" class="search-btnlist">
<a id="btnSave" class="hisui-linkbutton">保存</a>
<a id="btnClose" class="hisui-linkbutton">关闭</a>
</td>
</tr>
</table>
</div>
</body>
</html>
com.hisui.phm.js → com.sys.js → com.fun.js → base.css → component.js → 业务 JSclass="hisui-layout" + data-options="fit:true"north(上)、south(下)、west(左)、center(中)、east(右)phm.auth.js 后,按钮的 disabled:true 会根据后台配置自动控制,无需手动处理,不在 JS 中动态生成- 表格工具栏:通过
data-options="toolbar:'#ToolBar'" 关联 - 表单用
class="search-table",标签用 class="r-label",按钮区用 class="search-btnlist"
二、JS 编写规范
2.1 标准结构
信创版每个页面一个 JS 文件,包含:全局变量、组件初始化、事件绑定、数据加载,全部写在一个 .js 文件里。
// File: static/phm/模块名/scripts/xxx.js
// ========== 1. 页面全局变量对象 ==========
var globalObj = {
editId: "", // 当前编辑记录 ID
gridId: "", // 当前选中行 ID
// 其他页面状态...
};
// ========== 2. 页面入口(jQuery document ready) ==========
$(function () {
// 初始化按钮状态(单选场景:有选中时才允许编辑/删除)
$("#btnEdit").linkbutton("disable");
$("#btnDelete").linkbutton("disable");
// 初始化组件
initMain();
// 事件初始化
InitEvent();
// 初始化加载表格数据
loadGridData();
});
// ========== 3. 组件初始化 ==========
function initMain() {
// 初始化数据表格
$HUI.datagrid("#gridMain", {
fit: true,
headerCls: "panel-header-gray",
iconCls: "icon-paper",
rownumbers: true,
singleSelect: true,
autoRowHeight: false,
loadMsg: "数据加载中...",
pagination: true,
pageSize: 20,
pageList: [20, 50, 100, 200],
columns: [[
{ field: 'code', title: '代码', width: '150' },
{ field: 'displayname', title: '描述', width: '250' },
{ field: 'activity', title: '是否有效', width: '80',
formatter: function (value) {
return value == true ? "是" : "否";
}
},
{ field: 'id', title: 'ID', hidden: true }
]],
onSelect: function (rowIndex, rowData) {
// 防止重复选中同一行时无法取消
if (rowData.id == globalObj.gridId) {
$("#gridMain").datagrid("clearSelections");
$("#btnEdit").linkbutton("disable");
$("#btnDelete").linkbutton("disable");
globalObj.gridId = "";
} else {
globalObj.gridId = rowData.id;
$("#btnEdit").linkbutton("enable");
$("#btnDelete").linkbutton("enable");
}
},
onDblClickRow: function (rowIndex, rowData) {
editDialog(rowData);
},
onLoadSuccess: function (data) {
globalObj.gridId = "";
globalObj.editId = "";
$("#btnEdit").linkbutton("disable");
$("#btnDelete").linkbutton("disable");
}
});
// 初始化下拉框(如有)
$HUI.combobox("#cboProduct", {
url: PHM_COM.joinUrl(PHM_WIN.appPath, "phm/sys/xxx/selectList"),
method: 'POST',
onBeforeLoad: function (param) {
param.obj = { activity: true };
param.checkTime = true;
},
editable: true,
valueField: 'code',
textField: 'displayname'
});
// 初始化对话框(按钮在 JS 的 buttons 参数中定义)
$HUI.dialog("#winEdit", {
title: "编辑",
iconCls: "icon-w-paper",
closed: true,
modal: true,
isTopZindex: true,
width: 500,
height: 400,
buttons: [{
text: '保存',
handler: function () { saveData(); }
}, {
text: '关闭',
handler: function () { $HUI.dialog('#winEdit').close(); }
}]
});
}
// ========== 4. 事件绑定 ==========
function InitEvent() {
// 新增按钮(单选场景:有选中行时禁止新增)
$("#btnAdd").click(function () {
var rowData = $("#gridMain").datagrid("getSelected");
if (rowData) return false;
editDialog("");
});
// 修改按钮
$("#btnEdit").click(function () {
var rowData = $("#gridMain").datagrid("getSelected");
if (!rowData) {
$.messager.alert("提示", "请先选择对象", "info");
return false;
}
editDialog(rowData);
});
// 删除按钮
$("#btnDelete").click(function () {
var rowData = $("#gridMain").datagrid("getSelected");
if (!rowData) {
$.messager.alert("提示", "请先选择对象", "info");
return false;
}
deleteData();
});
// 查询按钮
$("#btnQuery").click(function () {
loadGridData();
});
}
// ========== 5. 数据加载 ==========
function loadGridData() {
$("#gridMain").datagrid("loading");
$ipost(PHM_COM.joinUrl(PHM_WIN.appPath, "phm/sys/xxx/selectList"), {
objXxx: {
// 查询条件从页面获取
}
}, function (result) {
if (result.success) {
// 前端分页:使用 PHM_COM.pagerFilter
$("#gridMain").datagrid({ loadFilter: PHM_COM.pagerFilter })
.datagrid("loadData", result.data || []);
} else {
$.messager.alert("提示", result.msg, "error");
}
$("#gridMain").datagrid("loaded");
});
}
// ========== 6. 对话框操作 ==========
function editDialog(rowData) {
if (rowData) {
// 修改模式:回填表单
globalObj.editId = rowData.id;
$("#txtCode").val(rowData.code);
$("#txtDesc").val(rowData.displayname);
$("#chkIsActive").checkbox("setValue", rowData.activity);
} else {
// 新增模式:清空表单
globalObj.editId = "";
$("#txtCode").val("");
$("#txtDesc").val("");
$("#chkIsActive").checkbox("setValue", true);
}
$HUI.dialog('#winEdit').open();
}
// ========== 7. 保存数据 ==========
function saveData() {
var code = $.trim($("#txtCode").val());
var desc = $.trim($("#txtDesc").val());
if (!code) { $.messager.alert("提示", "代码不能为空!"); return; }
if (!desc) { $.messager.alert("提示", "描述不能为空!"); return; }
var url = globalObj.editId
? "phm/sys/xxx/update"
: "phm/sys/xxx/insert";
$ipost(PHM_COM.joinUrl(PHM_WIN.appPath, url), {
id: globalObj.editId,
code: code,
displayname: desc,
activity: $("#chkIsActive").checkbox("getValue")
}, function (result) {
if (result.success) {
$.messager.popover({ msg: "保存成功!", type: 'success', timeout: 1000 });
$HUI.dialog('#winEdit').close();
loadGridData();
$("#gridMain").datagrid("clearSelections");
$("#btnEdit").linkbutton("disable");
$("#btnDelete").linkbutton("disable");
} else {
$.messager.alert("提示", result.msg, "error");
}
});
}
// ========== 8. 删除数据 ==========
function deleteData() {
var rowData = $("#gridMain").datagrid("getSelected");
$.messager.confirm('确认', '确定删除此记录?', function (r) {
if (r) {
$ipost(PHM_COM.joinUrl(PHM_WIN.appPath, "phm/sys/xxx/deleteById"), {
id: rowData.id
}, function (result) {
if (result.success) {
$.messager.popover({ msg: "删除成功!", type: 'success', timeout: 1000 });
loadGridData();
} else {
$.messager.popover({ msg: result.msg, type: 'error', timeout: 1000 });
}
});
}
});
}
2.2 关键点说明
- 全局变量用
globalObj:集中管理页面状态(editId、gridId 等),替代旧版分散的 obj.RecRowID - 入口用
$(function() { ... }):jQuery 标准就绪事件,不用 InitviewScreen() 模式 - API 路径拼接用
PHM_COM.joinUrl(PHM_WIN.appPath, "phm/..."):自动拼接上下文路径,适配不同部署环境 - 前端分页用
PHM_COM.pagerFilter:$("#grid").datagrid({ loadFilter: PHM_COM.pagerFilter }) 然后 loadData(result.data) - 响应格式:
result.success(布尔)、result.code(状态码)、result.msg(消息)、result.data(数据) - 对话框按钮在
buttons 参数中定义:不用 HTML onclick,统一在 $HUI.dialog() 的 buttons 中配置 - 按钮初始状态:页面加载时先
disable,选中行后再 enable(单选场景) - 防止重复选中:在
onSelect 中判断 rowData.id == globalObj.gridId 时调用 clearSelections() 取消选中
三、后台交互(数据访问)
> 需先引入 jQuery,再引入 websys.jquery.js。
3.1 $ipost — 向后台发送 POST 请求
> 默认以 request body - JSON 方式发送,对应 Spring Boot @PostMapping + @RequestBody。
语法
// 异步调用(推荐)
$ipost(allpath, param, successHandler, errorHandler);
// 同步调用(callback 传 false,返回后台结果)
var rtn = $ipost(allpath, param, false);
参数说明
参数 说明 ------ ------ allpath请求路径(如 /api/xxx/save) param请求参数对象 successHandler成功回调函数(异步),入参为后台返回的 JSON;传 false 时为同步调用 errorHandler错误回调函数(可选,仅异步有效)
示例代码
// 异步调用(常用)
$ipost('/api/sys/savemenu', { code: 'his', name: '菜单名' }, function(json) {
console.log(json); // 后台返回的 JSON 数据
});
// 同步调用(callback 传 false)
var rtn = $ipost('/api/xxx/getInfo', { id: globalObj.gridId }, false);
if (rtn && rtn.code === 200) {
var d = rtn.data;
$('#txtCode').val(d.code);
}
// 保存数据(常用模式)
$ipost(PHM_COM.joinUrl(PHM_WIN.appPath, "phm/sys/xxx/update"), {
id: globalObj.editId,
code: code,
displayname: desc
}, function(rtn) {
if (rtn && rtn.code === 200) {
$.messager.popover({ msg: '保存成功!', type: 'success', timeout: 1000 });
$("#gridMain").datagrid("reload");
} else {
$.messager.alert("错误提示", "保存失败! " + (rtn ? rtn.message : ''), 'info');
}
});
// 删除数据
$ipost(PHM_COM.joinUrl(PHM_WIN.appPath, "phm/sys/xxx/deleteById"), { id: globalObj.gridId }, function(rtn) {
if (rtn && rtn.code === 200) {
$.messager.popover({ msg: '删除成功!', type: 'success', timeout: 1000 });
$("#gridMain").datagrid("reload");
}
});
// 导出 Excel
$ipost('/api/xxx/list', { resultSetType: "excel", fileName: '数据列表' });
// 导出 PDF
$ipost('/api/xxx/list', { resultSetType: "pdf", fileName: '数据列表' });
// 导出并打印 PDF
$ipost('/api/xxx/list', { resultSetType: "excelPrint", printer: '' });
// 指定纸张大小(A3/A4)及方向(rotate: 0 或 90)
$ipost('/api/xxx/list', { resultSetType: "pdf", fileName: '文件名', pageSize: "A3", rotate: "90" });
// 导出时显示进度遮罩
$.messager.progress({ title: "提示", msg: 'Excel文件下载中', text: $g('下载中...') });
$ipost('/api/xxx/list', { p1: "参数", resultSetType: "excel", fileName: '文件名' }, function() {
$.messager.progress("close");
});
// 文件上传(FormData 方式)
function uploadFile() {
var fileObj = document.getElementById('upfile').files[0];
var formData = new FormData();
formData.append('file', fileObj);
$.messager.progress({ title: "提示", msg: '文件上传中', text: $g('上传中...') });
$ipost('/file/uploadReturnUrl', formData, function(rtn) {
$.messager.progress("close");
// rtn 包含后台返回的文件信息
});
}
对应 Java 后端示例
@PostMapping("/save")
public BaseResponse<Void> save(@RequestBody XXXDto dto) {
xxxService.save(dto);
return BaseResponse.success();
}
3.2 $iget — 向后台发送 GET 请求
> 默认使用 formdata 方式发送,对应 Spring Boot @GetMapping。
语法
// 异步调用(推荐)
$iget(allpath, param, successHandler, errorHandler);
// 同步调用(callback 传 false,返回后台结果)
var rtn = $iget(allpath, param, false);
参数说明
参数 说明 ------ ------ allpath请求路径(如 /api/xxx/detail) param请求参数对象 successHandler成功回调函数(异步),入参为后台返回的 JSON;传 false 时为同步调用 errorHandler错误回调函数(可选,仅异步有效)
示例代码
// 异步调用(推荐)
$iget('/api/xxx/detail', { id: globalObj.gridId }, function(json) {
if (json && json.data) {
var d = json.data;
$('#txtCode').val(d.code);
$('#txtDesc').val(d.description);
}
});
// 同步调用(callback 传 false)
var rtn = $iget(PHM_COM.joinUrl(PHM_WIN.appPath, "phm/sys/xxx/detail"), { id: globalObj.gridId }, false);
if (rtn && rtn.data) {
$('#txtCode').val(rtn.data.code);
}
// 查询列表
$iget('/api/xxx/list', { keyword: $('#txtName').val(), page: 1, size: 20 }, function(json) {
if (json && json.data) {
$("#gridMain").datagrid("loadData", json.data);
}
});
// 获取下拉数据
$iget('/api/xxx/combo', { type: 'DEPT', isActive: 1 }, function(json) {
if (json && json.data) {
$('#cboDept').combobox('loadData', json.data);
}
});
对应 Java 后端示例
@GetMapping("/detail")
public BaseResponse<XXXVo> detail(String id) {
XXXVo vo = xxxService.getById(id);
return BaseResponse.success(vo);
}
3.3 $ipost_enc / $iget_enc — 全参数加密请求
> 发送请求前将所有参数加密,后台 Java 使用 @InterfaceDecrypt 解密。
$iget_enc 示例(GET 全参数加密)
$iget_enc('/api/user/login', {
password: "123456",
username: "doctor01",
loc: '所有科室'
}, function(rtn) {
console.log(rtn.data);
});
对应 Java:
@GetMapping("/login")
@InterfaceDecrypt
public BaseResponse<UserVo> login(String password, String username, String loc) {
return BaseResponse.success(userVo);
}
$ipost_enc 示例(POST 全参数加密)
$ipost_enc('/api/user/login', {
password: "123456",
username: "doctor01",
loc: '所有科室'
}, function(rtn) {
console.log(rtn.data);
});
对应 Java:
@PostMapping("/login")
@InterfaceDecrypt
public BaseResponse<UserDto> login(@RequestBody UserDto dto) {
return BaseResponse.success(dto);
}
3.4 websys_interfaceEncrypt — 部分参数加密
> 只对指定参数加密,其余参数明文传输,后台使用 @InterfaceDecrypt(keyParams/bodyParams) 解密指定参数。
// GET 部分参数加密
var passwordEnc = websys_interfaceEncrypt("123456");
var usernameEnc = websys_interfaceEncrypt("admin");
$iget('/api/user/login', {
password: passwordEnc,
username: usernameEnc,
loc: '部分科室'
}, function(rtn) {
console.log(rtn.data);
});
对应 Java:
@GetMapping("/login")
@InterfaceDecrypt(keyParams = {"password", "username"})
public BaseResponse<UserVo> login(String password, String username, String loc) {
return BaseResponse.success(userVo);
}
四、前端公共方法
4.1 头菜单表单(全局参数读写)
> 头菜单表单用于存储全局参数,如:病人ID、就诊ID、就诊类型、手术ID、会诊ID、DoingSth 等。
常用表单属性
属性名 说明 -------- ------ EpisodeID就诊ID(传此值时 admType 也需传入) PatientID患者ID DoingSth正在做某事说明,不为空时切换菜单会弹出提示 admType患者就诊类型(用于患者信息条和诊断录入界面) PACSApplyNo医技申请单号 AppointmentID手术申请ID PlannedOperationID拟施手术id
websys_resetMenuForm — 重设头菜单表单
// 重置所有表单(全初始化)
websys_resetMenuForm();
// 强制处理全局头菜单就诊信息
websys_resetMenuForm(true);
websys_getMenuForm — 从头菜单表单获取值
var frm = websys_getMenuForm();
var episodeId = frm.EpisodeID.value;
var patientId = frm.PatientID.value;
var admType = frm.admType.value;
// 强制处理全局头菜单就诊信息
websys_getMenuForm(true);
websys_setMenuForm — 设置头菜单表单值
> ⚠️ 会先清空所有表单信息,再将参数写入全局表单。
> ⚠️ 除 DoingSth 外,禁止直接用 x.value=x 赋值,必须使用此方法。
websys_setMenuForm({ PatientID: 1, EpisodeID: 2, admType: 'I' });
websys_setMenuForm({ PatientID: 1, EpisodeID: 2, admType: 'I', canGiveBirth: 1 });
websys_setMenuForm({ PatientID: 1, EpisodeID: 2, admType: 'I', AppointmentID: 1 });
// 强制处理全局头菜单就诊信息
websys_setMenuForm({ EpisodeID: 2, PatientID: 1, admType: 'I' }, true);
// DoingSth 可直接赋值
var frm = websys_getMenuForm();
frm.DoingSth.value = "病历文书正在编辑中,是否保存";
4.2 websys_getSession — 获得当前会话信息
var session = websys_getSession();
4.3 websys_getMenuWin — 获得头菜单 Window 对象
var menuWin = websys_getMenuWin();
4.4 websys_showModal — 弹出 HISUI 窗口
在顶层窗口弹出
websys_showModal({
title: '弹出窗口',
width: 700,
height: 400,
url: '../base/runqian/html/test.html?open=2',
myData: { startDate: '2024-12-09' } // 附加参数对象
});
// 在弹出界面中获得附加参数
var myData = websys_showModal('options').myData; // {startDate:'2024-12-09'}
// 关闭窗口
websys_showModal('close');
在指定 iframe 区域内弹出
websys_showModal({
title: '弹出窗口',
width: 700,
height: 400,
targetFrm: window, // 也可用 targetName:"MyName" 指定 iframe 名称
url: '../../../base/runqian/html/test.html?open=1',
myData: { startDate: '2024-12-09' }
});
// 在 test.html 中获得附加参数
var myData = websys_showModal('options', { targetFrm: window.parent }).myData;
// 关闭窗口
websys_showModal('close', { targetFrm: window.parent });
4.5 链接路径相关方法
websys_rewriteUrl — 为 URL 增加请求参数
websys_rewriteUrl("my.html?id=1", { id: 2, name: 'whc' }); // 返回:my.html?id=2&name=whc
websys_rewriteUrl("my.html", { id: 2, name: 'whc' }); // 返回:my.html?id=2&name=whc
websys_rewriteUrl("", { id: 2, name: 'whc' }); // 返回:?id=2&name=whc
websys_frontPathCombine — 相对路径转绝对路径
// 相对于 static/base/ 的 html 路径,生成绝对路径
websys_frontPathCombine("../emr/ip/html/my.html");
// 返回:/his/base/../emr/ip/html/my.html
// 以 / 或 // 开头时不处理
websys_frontPathCombine("//emr/ip/html/my.html"); // 返回://emr/ip/html/my.html
websys_urlToParamObj — 获取 URL 中的参数对象
websys_urlToParamObj(location.href); // 返回当前界面的请求参数对象
websys_urlToParamObj("my.html?id=1&name=whc"); // 返回:{id:1, name:"whc"}
websys_urlToParamObj("id=1&name=whc"); // 返回:{id:1, name:"whc"}
websys_objToParam — 在已有参数串中补充参数
// containEmpty 为 false 或不传时,忽略 obj 中的空值
websys_objToParam({ id: 1 }, "id=2&type=", true); // 返回:'id=2&type='
websys_objToParam({ id: 1, sex: '' }, "id=2&type=", false); // 返回:'id=2&type='
4.6 websys_createWindow — 创建新窗口
websys_createWindow('my.html', '_blank');
websys_createWindow('my.html', 'TRAK_hidden', 'status,scrollbars,resizable,hisui=true,width=80%,height=80%');
4.7 Token 相关方法
// 获得登录的 token 值
websys_getHosAccessToken();
// 等价于:window.sessionStorage.getItem("hispro__access-token")
// 通用方法获取 sessionStorage 中的值
websys_getHosStorageItemValue('access-token'); // 获取 token
websys_getHosStorageItemValue('HostName'); // 获取 HostName 值
// 也可使用 HOS 基础平台封装的方法
window.hos_utils.ls.get('access-token');
4.8 websys_getTop — 获得同域最顶层 Window
var myTop = websys_getTop();
// 一直向上查找 parent,遇到跨域则返回当前 window
4.9 $g — 国际化翻译方法
// 基础用法
$g('notNull.code'); // 返回:代码不能为空
// 数组占位符
$g('password.errorTimes', [3, 2]); // 返回:你已错误登录3次,还有2机会
// 字符串内联占位符(索引方式)
$g('你已错误登录{0}次,还有{1}机会', [3, 2]); // 返回:你已错误登录3次,还有2机会
// 字符串内联占位符(命名方式)
$g('你已错误登录{etimes}次,还有{rtimes}机会', { etimes: 3, rtimes: 2 });
// 返回:你已错误登录3次,还有2机会
HTML 内翻译:
<td class="hisui-label">姓名</td>
<span class="hisui-label">登记号</span>
4.10 websys_printByRunQian — 润乾打印方法
<!-- 引入公共打印 JS -->
<script src="../../scripts/websys.print.comm.js"></script>
websys_printByRunQian({
reportName: "bsp/sys/test", // 不带后缀,必填
needSelectPrinter: 'yes', // 是否需要用户选择打印机(yes/no,默认 no)
printerName: '打印机名称', // 打印机名
reportParam: { // 会自动加上 session 中信息作为参数
stDate: '2023-11-18',
endDate: '2023-11-19'
}
});
五、核心组件使用示例
5.1 数据表格(Datagrid)
// 初始化
$HUI.datagrid("#gridMain", {
fit: true,
title: "病人列表",
headerCls: 'panel-header-gray',
iconCls: 'icon-paper',
pagination: true,
rownumbers: true,
singleSelect: true,
autoRowHeight: false,
pageSize: 20,
pageList: [20, 50, 100, 200],
url: PHM_COM.joinUrl(PHM_WIN.appPath, "phm/sys/xxx/selectList"),
method: 'post',
columns: [[
{ field: 'code', title: '编码', width: 100 },
{ field: 'name', title: '姓名', width: 120 },
{ field: 'dept', title: '科室', width: 100 },
{ field: 'diag', title: '诊断', width: 150 },
{ field: 'id', title: 'ID', hidden: true }
]],
onDblClickRow: function(rowIndex, rowData) {
editDialog(rowData);
},
onSelect: function(rowIndex, rowData) {
if (rowIndex > -1) {
// 防止重复选中
if (rowData.id == globalObj.gridId) {
$("#gridMain").datagrid("clearSelections");
globalObj.gridId = "";
} else {
globalObj.gridId = rowData.id;
}
}
}
});
5.2 放大镜(Lookup)
// 初始化(远程搜索)
$HUI.lookup("#cbgLookup", {
width: 260,
panelWidth: 600,
url: PHM_COM.joinUrl(PHM_WIN.appPath, "phm/sys/dept/selectList"),
method: 'post',
editable: true,
mode: 'remote',
idField: 'id',
textField: 'name',
columns: [[
{ field: 'code', title: '代码', width: 100 },
{ field: 'name', title: '名称', width: 240 }
]],
pagination: true,
onBeforeLoad: function(param) {
var q = param['q'];
if (q == "") return false;
param = $.extend(param, { keyword: q });
},
onSelect: function(rindex, rowData) {
if (rindex > -1) {
globalObj.gridId = rowData.id;
}
},
loadMsg: '正在查询',
isCombo: true,
minQueryLen: 0
});
5.3 下拉框(Combobox)
// 初始化
$HUI.combobox("#cboDept", {
url: PHM_COM.joinUrl(PHM_WIN.appPath, "phm/sys/dict/selectList"),
valueField: 'code',
textField: 'displayname',
editable: true,
onBeforeLoad: function(param) {
param.type = 'DEPT';
param.isActive = 1;
}
});
5.4 对话框(Dialog)
// 初始化(按钮在 buttons 参数中定义)
$HUI.dialog("#winEdit", {
title: '编辑窗口',
iconCls: 'icon-w-paper',
closed: true,
modal: true,
isTopZindex: true,
width: 500,
height: 400,
buttons: [{
text: '保存',
iconCls: 'icon-w-save',
handler: function() { saveData(); }
}, {
text: '关闭',
iconCls: 'icon-w-close',
handler: function() { $HUI.dialog('#winEdit').close(); }
}]
});
// 操作
$HUI.dialog('#winEdit').open();
$HUI.dialog('#winEdit').close();
$HUI.dialog('#winEdit').dialog('setTitle', '新标题');
六、前端方法速查汇总表
方法名 类型 说明 -------- ------ ------ $ipost(path, param, callback, error)HTTP POST 请求(JSON body),callback 为 false 时同步 $iget(path, param, callback, error)HTTP GET 请求(formdata),callback 为 false 时同步 $ipost_enc(path, param, success)HTTP POST 全参数加密请求 $iget_enc(path, param, success)HTTP GET 全参数加密请求 websys_interfaceEncrypt(value)加密 对单个值加密(部分参数加密场景) websys_getMenuWin()窗口 获得头菜单 Window 对象 websys_getSession()会话 获得当前会话信息 websys_resetMenuForm(forceGlobal?)表单 重置头菜单表单 websys_getMenuForm(forceGlobal?)表单 获取头菜单表单 websys_setMenuForm(options, forceGlobal?)表单 设置头菜单表单 websys_showModal(options)窗口 弹出 HISUI 窗口 websys_rewriteUrl(url, paramObj)URL 为 URL 增加参数 websys_frontPathCombine(url)URL 相对路径转绝对路径 websys_urlToParamObj(url)URL 解析 URL 参数为对象 websys_objToParam(obj, origin, containEmpty)URL 补充参数到参数串 websys_createWindow(url, name, features)窗口 创建新窗口 websys_getHosAccessToken()Token 获取登录 token websys_getHosStorageItemValue(key)Token 获取 sessionStorage 值 websys_getTop()窗口 获得同域最顶层 window $g(key, params?)国际化 翻译文本 websys_printByRunQian(options)打印 润乾报表打印
七、常用提示信息
7.1 Popover 提示(推荐)
// 成功提示
$.messager.popover({ msg: '保存成功!', type: 'success', timeout: 1000 });
// 错误提示
$.messager.popover({ msg: '保存失败!', type: 'error', timeout: 2000 });
// 警告提示
$.messager.popover({ msg: '请先选择数据!', type: 'warning', timeout: 1500 });
7.2 Alert 对话框
// 信息提示
$.messager.alert("提示", "操作成功!", 'info');
// 错误提示
$.messager.alert("错误提示", "保存失败!", 'error');
// 确认框
$.messager.confirm('确认', '确定要删除吗?', function(r) {
if (r) {
$ipost(PHM_COM.joinUrl(PHM_WIN.appPath, "phm/sys/xxx/deleteById"), { id: globalObj.gridId }, function(rtn) {
if (rtn && rtn.code === 200) {
$.messager.popover({ msg: '删除成功!', type: 'success', timeout: 1000 });
$("#gridMain").datagrid("reload");
}
});
}
});
八、最佳实践
8.1 性能优化
- 表格设置
autoRowHeight: false - 提高渲染性能 - 使用分页 -
pagination: true,每页不超过 200 条 - 缓存对象 - 将常用组件赋值给变量,避免重复查找 DOM
- 放大镜使用
mode:'remote' - 远程搜索,避免一次性加载大量数据
8.2 代码组织
- 每页两个文件 -
html/xxx.html + scripts/xxx.js - JS 入口用
$(function(){}) - 不用 InitviewScreen() 旧模式 - 全局状态用
globalObj - 集中管理,替代分散变量 - 函数命名清晰 -
initMain()、InitEvent()、loadGridData()、editDialog()、saveData()、deleteData() $ipost 优先 - 统一使用 POST 方式,避免参数暴露在 URL
8.3 错误处理
// 统一错误处理
function showError(msg) {
$.messager.alert("错误提示", msg, 'info');
}
// 带错误回调的请求
$ipost(PHM_COM.joinUrl(PHM_WIN.appPath, "phm/sys/xxx/save"), param, function(rtn) {
if (rtn && rtn.code === 200) {
$.messager.popover({ msg: '操作成功!', type: 'success', timeout: 1000 });
} else {
showError("操作失败: " + (rtn ? rtn.message : '网络异常'));
}
}, function(err) {
showError("请求失败,请检查网络连接");
});
// 数据校验
function validateForm() {
var errinfo = "";
if (!$.trim($('#txtCode').val())) errinfo += "代码不能为空!<br>";
if (!$.trim($('#txtDesc').val())) errinfo += "描述不能为空!<br>";
if (errinfo) {
showError(errinfo);
return false;
}
return true;
}
九、常见问题
Q1: $ipost 和 $iget 有什么区别?
A: $ipost 以 JSON body 方式发送 POST 请求,适合新增/修改/删除;$iget 以 formdata 方式发送 GET 请求,适合查询详情。一般来说优先使用 $ipost,安全性更好。
Q1b: 如何使用同步调用?
A: 将 callback 参数传 false,方法会直接返回结果(阻塞当前线程,仅在必要时使用):
// $ipost 同步
var rtn = $ipost(PHM_COM.joinUrl(PHM_WIN.appPath, "phm/sys/xxx/getInfo"), { id: globalObj.gridId }, false);
if (rtn && rtn.code === 200) { ... }
// $iget 同步
var rtn = $iget(PHM_COM.joinUrl(PHM_WIN.appPath, "phm/sys/xxx/detail"), { id: globalObj.gridId }, false);
if (rtn && rtn.data) { ... }
Q2: 如何在 $ipost/$iget 中处理错误?
A: 在第四个参数传入 errorHandler 函数:
$ipost('/api/xxx', param, function(rtn) {
// 成功
}, function(err) {
$.messager.alert("提示", "请求失败", 'error');
});
Q3: 怎么确认后台返回的数据结构?
A: 通常 Java 后端统一返回 BaseResponse 结构:
{
"code": 200,
"message": "success",
"data": { ... }
}
前端通过 rtn.code === 200 判断成功,通过 rtn.data 获取数据,通过 rtn.message 获取提示信息。
Q4: 表格分页参数如何传递?
A: 表格会自动传入 page(页码)和 rows(每页条数)参数,后端可用分页对象处理(如 PageRequest.of(page - 1, rows))。前端使用 PHM_COM.pagerFilter 实现前端分页。
Q5: 对话框无法置顶?
A: 设置 isTopZindex: true
Q6: 按钮禁用后仍然触发事件?
A: 使用 stopAllEventOnDisabled: true 配置项
十、图标参考
icon-w-find - 查找icon-w-ok - 确定icon-w-cancel - 取消icon-w-edit - 编辑icon-w-delete - 删除icon-w-save - 保存icon-w-paper - 文档icon-write-order - 修改icon-add - 新增icon-resort - 排序
使用示例:
<a class="hisui-linkbutton" data-options="iconCls:'icon-w-save'">保存</a>
十一、参考资料
- 前端公共方法文档:
http://hisui.cn/bsp/dev/front/ - HISUI 组件文档:
http://hisui.cn/api/ - EasyUI 文档:
http://www.jeasyui.com/documentation/
版本: v20260611(信创版)
适用场景: 医疗信息系统(HIS、EMR、LIS 等)Java 后端
技术栈: HISUI(EasyUI 二次开发)+ Spring Boot
共 1 个版本