fix(core): 解决ID字段精度丢失和账户ID为空问题

- 在前端请求处理中添加convertIdsToString函数,将超过安全范围的数字转换为字符串
- 使用json-bigint库处理大数字序列化,防止精度丢失
- 在医嘱保存逻辑中确保accountId不为null,自动创建自费账户
- 添加IAccountService依赖注入支持账户操作
- 在产品转移详情DTO中添加@TableField注解标识非数据库字段
This commit is contained in:
2026-03-26 15:36:17 +08:00
parent 8739959be0
commit f04c3d112c
5 changed files with 123 additions and 5 deletions

View File

@@ -1104,6 +1104,28 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
log.info("BugFix#219: ========== handDevice END =========="); log.info("BugFix#219: ========== handDevice END ==========");
for (AdviceSaveDto adviceSaveDto : insertOrUpdateList) { for (AdviceSaveDto adviceSaveDto : insertOrUpdateList) {
// 🔧 Bug Fix: 确保accountId不为null
if (adviceSaveDto.getAccountId() == null) {
// 尝试从患者就诊中获取默认账户ID自费账户
Account selfAccount = iAccountService.getSelfAccount(adviceSaveDto.getEncounterId());
if (selfAccount != null) {
adviceSaveDto.setAccountId(selfAccount.getId());
} else {
// 自动创建自费账户
Account newAccount = new Account();
newAccount.setPatientId(adviceSaveDto.getPatientId());
newAccount.setEncounterId(adviceSaveDto.getEncounterId());
newAccount.setContractNo(CommonConstants.BusinessName.DEFAULT_CONTRACT_NO);
newAccount.setTypeCode(AccountType.PERSONAL_CASH_ACCOUNT.getCode());
newAccount.setBalanceAmount(BigDecimal.ZERO);
newAccount.setStatusEnum(AccountStatus.ACTIVE.getValue());
newAccount.setEncounterFlag(Whether.YES.getValue());
newAccount.setName(AccountType.PERSONAL_CASH_ACCOUNT.getInfo());
Long newAccountId = iAccountService.saveAccountByRegister(newAccount);
adviceSaveDto.setAccountId(newAccountId);
}
}
deviceRequest = new DeviceRequest(); deviceRequest = new DeviceRequest();
deviceRequest.setId(adviceSaveDto.getRequestId()); // 主键id deviceRequest.setId(adviceSaveDto.getRequestId()); // 主键id
deviceRequest.setStatusEnum(is_save ? RequestStatus.DRAFT.getValue() : RequestStatus.ACTIVE.getValue()); // 请求状态 deviceRequest.setStatusEnum(is_save ? RequestStatus.DRAFT.getValue() : RequestStatus.ACTIVE.getValue()); // 请求状态

View File

@@ -10,8 +10,10 @@ import com.core.common.utils.AssignSeqUtil;
import com.core.common.utils.MessageUtils; import com.core.common.utils.MessageUtils;
import com.core.common.utils.SecurityUtils; import com.core.common.utils.SecurityUtils;
import com.core.common.utils.StringUtils; import com.core.common.utils.StringUtils;
import com.openhis.administration.domain.Account;
import com.openhis.administration.domain.ChargeItem; import com.openhis.administration.domain.ChargeItem;
import com.openhis.administration.domain.EncounterDiagnosis; import com.openhis.administration.domain.EncounterDiagnosis;
import com.openhis.administration.service.IAccountService;
import com.openhis.administration.service.IChargeItemService; import com.openhis.administration.service.IChargeItemService;
import com.openhis.administration.service.IEncounterDiagnosisService; import com.openhis.administration.service.IEncounterDiagnosisService;
import com.openhis.clinical.domain.Condition; import com.openhis.clinical.domain.Condition;
@@ -80,6 +82,9 @@ public class DoctorStationChineseMedicalAppServiceImpl implements IDoctorStation
@Resource @Resource
AdviceUtils adviceUtils; AdviceUtils adviceUtils;
@Resource
IAccountService iAccountService;
/** /**
* 查询中医诊断数据 * 查询中医诊断数据
* *
@@ -475,6 +480,28 @@ public class DoctorStationChineseMedicalAppServiceImpl implements IDoctorStation
// 医嘱签发编码 // 医嘱签发编码
String signCode = assignSeqUtil.getSeq(AssignSeqEnum.ADVICE_SIGN.getPrefix(), 10); String signCode = assignSeqUtil.getSeq(AssignSeqEnum.ADVICE_SIGN.getPrefix(), 10);
for (AdviceSaveDto adviceSaveDto : insertOrUpdateList) { for (AdviceSaveDto adviceSaveDto : insertOrUpdateList) {
// 🔧 Bug Fix: 确保accountId不为null
if (adviceSaveDto.getAccountId() == null) {
// 尝试从患者就诊中获取默认账户ID自费账户
Account selfAccount = iAccountService.getSelfAccount(adviceSaveDto.getEncounterId());
if (selfAccount != null) {
adviceSaveDto.setAccountId(selfAccount.getId());
} else {
// 自动创建自费账户
Account newAccount = new Account();
newAccount.setPatientId(adviceSaveDto.getPatientId());
newAccount.setEncounterId(adviceSaveDto.getEncounterId());
newAccount.setContractNo(CommonConstants.BusinessName.DEFAULT_CONTRACT_NO);
newAccount.setTypeCode(AccountType.PERSONAL_CASH_ACCOUNT.getCode());
newAccount.setBalanceAmount(BigDecimal.ZERO);
newAccount.setStatusEnum(AccountStatus.ACTIVE.getValue());
newAccount.setEncounterFlag(Whether.YES.getValue());
newAccount.setName(AccountType.PERSONAL_CASH_ACCOUNT.getInfo());
Long newAccountId = iAccountService.saveAccountByRegister(newAccount);
adviceSaveDto.setAccountId(newAccountId);
}
}
// 中药付数 // 中药付数
BigDecimal chineseHerbsDoseQuantity = adviceSaveDto.getChineseHerbsDoseQuantity(); BigDecimal chineseHerbsDoseQuantity = adviceSaveDto.getChineseHerbsDoseQuantity();
medicationRequest = new MedicationRequest(); medicationRequest = new MedicationRequest();

View File

@@ -11,6 +11,8 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.openhis.administration.domain.ChargeItem; import com.openhis.administration.domain.ChargeItem;
import com.openhis.administration.domain.Account;
import com.openhis.administration.service.IAccountService;
import com.openhis.administration.service.IChargeItemService; import com.openhis.administration.service.IChargeItemService;
import com.openhis.common.constant.CommonConstants; import com.openhis.common.constant.CommonConstants;
import com.openhis.common.enums.*; import com.openhis.common.enums.*;
@@ -71,6 +73,9 @@ public class AdviceUtils {
@Resource @Resource
IDoctorStationAdviceAppService iDoctorStationAdviceAppService; IDoctorStationAdviceAppService iDoctorStationAdviceAppService;
@Resource
IAccountService iAccountService;
/** /**
* 校验库存 * 校验库存
* *
@@ -305,6 +310,28 @@ public class AdviceUtils {
*/ */
public void handleActivityChild(String childrenJson, Long organizationId, public void handleActivityChild(String childrenJson, Long organizationId,
ActivityChildrenJsonParams activityChildrenJsonParams) { ActivityChildrenJsonParams activityChildrenJsonParams) {
// 🔧 Bug Fix: 确保accountId不为null
if (activityChildrenJsonParams.getAccountId() == null) {
// 尝试从患者就诊中获取默认账户ID自费账户
Account selfAccount = iAccountService.getSelfAccount(activityChildrenJsonParams.getEncounterId());
if (selfAccount != null) {
activityChildrenJsonParams.setAccountId(selfAccount.getId());
} else {
// 自动创建自费账户
Account newAccount = new Account();
newAccount.setPatientId(activityChildrenJsonParams.getPatientId());
newAccount.setEncounterId(activityChildrenJsonParams.getEncounterId());
newAccount.setContractNo(CommonConstants.BusinessName.DEFAULT_CONTRACT_NO);
newAccount.setTypeCode(AccountType.PERSONAL_CASH_ACCOUNT.getCode());
newAccount.setBalanceAmount(BigDecimal.ZERO);
newAccount.setStatusEnum(AccountStatus.ACTIVE.getValue());
newAccount.setEncounterFlag(Whether.YES.getValue());
newAccount.setName(AccountType.PERSONAL_CASH_ACCOUNT.getInfo());
Long newAccountId = iAccountService.saveAccountByRegister(newAccount);
activityChildrenJsonParams.setAccountId(newAccountId);
}
}
// 治疗类型 (长期/临时) // 治疗类型 (长期/临时)
Integer therapyEnum = activityChildrenJsonParams.getTherapyEnum(); Integer therapyEnum = activityChildrenJsonParams.getTherapyEnum();
// 当前登录账号的科室id // 当前登录账号的科室id

View File

@@ -4,6 +4,7 @@
package com.openhis.web.inventorymanage.dto; package com.openhis.web.inventorymanage.dto;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.core.common.annotation.Excel; import com.core.common.annotation.Excel;
import com.core.common.annotation.ExcelExtra; import com.core.common.annotation.ExcelExtra;
@@ -248,7 +249,8 @@ public class ProductTransferDetailDto {
private Date occurrenceTime; private Date occurrenceTime;
/** /**
* 单位列表 * 单位列表(非数据库字段,业务逻辑填充)
*/ */
@TableField(exist = false)
private List<UnitDto> unitList; private List<UnitDto> unitList;
} }

View File

@@ -11,6 +11,38 @@ import JSONBig from 'json-bigint'
// 初始化json-bigint配置大数字转字符串关键storeAsString: true // 初始化json-bigint配置大数字转字符串关键storeAsString: true
const jsonBig = JSONBig({ storeAsString: true }) const jsonBig = JSONBig({ storeAsString: true })
// 🔧 Bug Fix #281: 转换所有ID字段为字符串防止BigInt精度丢失
const convertIdsToString = (obj) => {
if (obj === null || obj === undefined) return obj
if (typeof obj === 'number' && obj > 9007199254740991) {
// 如果是超过安全范围的数字,转为字符串
return String(obj)
}
if (typeof obj === 'object') {
if (Array.isArray(obj)) {
return obj.map(item => convertIdsToString(item))
} else {
const newObj = {}
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
const value = obj[key]
// 如果key以Id结尾或者是id且值是数字转为字符串
if ((key === 'id' || key.endsWith('Id') || key.endsWith('ID')) && typeof value === 'number') {
newObj[key] = String(value)
} else {
newObj[key] = convertIdsToString(value)
}
}
}
return newObj
}
}
return obj
}
let downloadLoadingInstance; let downloadLoadingInstance;
// 是否显示重新登录 // 是否显示重新登录
export let isRelogin = { show: false }; export let isRelogin = { show: false };
@@ -35,16 +67,23 @@ const service = axios.create({
} }
} }
], ],
// 可选:请求体序列化,无需额外处理,默认即可(保留也不影响) // 可选:请求体序列化,使用json-bigint处理大数字
transformRequest: [ transformRequest: [
function (data) { function (data) {
return JSON.stringify(data) if (!data) return data
// 🔧 Bug Fix #281: 使用json-bigint序列化保留大数字精度
return jsonBig.stringify(data)
} }
] ]
}) })
// request拦截器 // request拦截器
service.interceptors.request.use(config => { service.interceptors.request.use(config => {
// 🔧 Bug Fix #281: 转换请求数据中的ID字段为字符串
if (config.data && typeof config.data === 'object') {
config.data = convertIdsToString(config.data)
}
// 是否需要设置 token // 是否需要设置 token
const isToken = (config.headers || {}).isToken === false const isToken = (config.headers || {}).isToken === false
// 是否需要防止数据重复提交 // 是否需要防止数据重复提交
@@ -62,10 +101,11 @@ service.interceptors.request.use(config => {
if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) { if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) {
const requestObj = { const requestObj = {
url: config.url, url: config.url,
data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data, data: typeof config.data === 'object' ? jsonBig.stringify(config.data) : config.data,
time: new Date().getTime() time: new Date().getTime()
} }
const requestSize = Object.keys(JSON.stringify(requestObj)).length; // 请求数据大小 // 🔧 Bug Fix #281: 使用json-bigint计算大小
const requestSize = Object.keys(jsonBig.stringify(requestObj)).length; // 请求数据大小
const limitSize = 5 * 1024 * 1024; // 限制存放数据5M const limitSize = 5 * 1024 * 1024; // 限制存放数据5M
if (requestSize >= limitSize) { if (requestSize >= limitSize) {
console.warn(`[${config.url}]: ` + '请求数据大小超出允许的5M限制无法进行防重复提交验证。') console.warn(`[${config.url}]: ` + '请求数据大小超出允许的5M限制无法进行防重复提交验证。')