Compare commits
25 Commits
7f2f612e58
...
zhaoyun
| Author | SHA1 | Date | |
|---|---|---|---|
| 4693c0d4c0 | |||
| 750efffa8b | |||
| fa23375050 | |||
| 8164cec57a | |||
| babf62083a | |||
| 68cfa48820 | |||
|
|
d47c83eec5 | ||
|
|
2915915881 | ||
| 68b92dfe31 | |||
| c9e8729d07 | |||
| 207640f4ef | |||
| 566ce61293 | |||
|
|
a04fa368b1 | ||
| f940078208 | |||
| 06363ec191 | |||
|
|
3c8d5e94a3 | ||
|
|
6f7f6dc9f5 | ||
|
|
376ddd46ff | ||
| e1ab9fba23 | |||
| f458835183 | |||
|
|
57f591e1c0 | ||
|
|
a98a03e00a | ||
| fddf1c2d03 | |||
|
|
c7f85ff20d | ||
|
|
72ab38f5d0 |
@@ -1,3 +1,4 @@
|
||||
|
||||
# 前端发布前检查清单
|
||||
|
||||
> **文档类型**: 技术规范
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"test_time": "2026-06-08T09:11:33.934379",
|
||||
"test_time": "2026-06-08T11:20:49.248056",
|
||||
"environment": "http://localhost:18082/healthlink-his",
|
||||
"total": 125,
|
||||
"passed": 125,
|
||||
@@ -167,7 +167,7 @@
|
||||
"id": "OP-PHARM",
|
||||
"name": "待发药列表",
|
||||
"ok": true,
|
||||
"detail": "待发药=534"
|
||||
"detail": "待发药=532"
|
||||
},
|
||||
{
|
||||
"id": "OP-WEST",
|
||||
@@ -377,13 +377,13 @@
|
||||
"id": "INS-3D",
|
||||
"name": "3D重建任务",
|
||||
"ok": true,
|
||||
"detail": "任务=0"
|
||||
"detail": "任务=14"
|
||||
},
|
||||
{
|
||||
"id": "INS-3D-RPT",
|
||||
"name": "3D重建报告",
|
||||
"ok": true,
|
||||
"detail": "报告=0"
|
||||
"detail": "报告=11"
|
||||
},
|
||||
{
|
||||
"id": "INS-RAD-RPT",
|
||||
@@ -695,7 +695,7 @@
|
||||
"id": "MR-05-PHARM",
|
||||
"name": "药师→待发药",
|
||||
"ok": true,
|
||||
"detail": "待发药=534"
|
||||
"detail": "待发药=532"
|
||||
},
|
||||
{
|
||||
"id": "MR-06-CHARGE",
|
||||
|
||||
@@ -1,83 +1,56 @@
|
||||
package com.core.framework.config;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.jackson2.autoconfigure.Jackson2ObjectMapperBuilderCustomizer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* 程序注解配置
|
||||
*
|
||||
* @author system
|
||||
*/
|
||||
@Configuration
|
||||
// 表示通过aop框架暴露该代理对象,AopContext能够访问
|
||||
@EnableAspectJAutoProxy(exposeProxy = true)
|
||||
// 指定要扫描的Mapper类的包的路径
|
||||
@MapperScan({"com.core.**.mapper", "com.healthlink.his.**.mapper"})
|
||||
public class ApplicationConfig {
|
||||
private static final Logger log = LoggerFactory.getLogger(ApplicationConfig.class);
|
||||
|
||||
/** 支持多种日期格式的反序列化器 */
|
||||
private static final JsonDeserializer<LocalDateTime> LOCAL_DATE_TIME_DESERIALIZER = new JsonDeserializer<LocalDateTime>() {
|
||||
private static final JsonDeserializer<LocalDateTime> LOCAL_DATE_TIME_DESERIALIZER = new JsonDeserializer<>() {
|
||||
private static final DateTimeFormatter ISO_FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
|
||||
private static final DateTimeFormatter SIMPLE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
private static final DateTimeFormatter SLASH_FORMATTER = DateTimeFormatter.ofPattern("yyyy/M/d HH:mm:ss");
|
||||
|
||||
@Override
|
||||
public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
|
||||
public LocalDateTime deserialize(JsonParser p, DeserializationContext context) throws IOException {
|
||||
String text = p.getText();
|
||||
if (text == null || text.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
// 去除时区后缀 Z/z 和偏移量 +HH:MM/+HHMM(LocalDateTime 不含时区信息)
|
||||
if (text == null || text.isEmpty()) return null;
|
||||
String cleaned = text.replaceAll("[Zz]$", "").replaceAll("[+-]\\d{2}:?\\d{2}$", "");
|
||||
// 尝试 ISO 8601 格式(yyyy-MM-ddTHH:mm:ss.SSS)
|
||||
try {
|
||||
return LocalDateTime.parse(cleaned, ISO_FORMATTER);
|
||||
} catch (Exception ignored) {
|
||||
// intentionally ignored
|
||||
}
|
||||
// 尝试简单格式(yyyy-MM-dd HH:mm:ss)
|
||||
try {
|
||||
return LocalDateTime.parse(cleaned, SIMPLE_FORMATTER);
|
||||
} catch (Exception ignored) {
|
||||
// intentionally ignored
|
||||
}
|
||||
// 尝试斜杠格式(yyyy/M/d HH:mm:ss)
|
||||
try { return LocalDateTime.parse(cleaned, ISO_FORMATTER); } catch (Exception ignored) {}
|
||||
try { return LocalDateTime.parse(cleaned, SIMPLE_FORMATTER); } catch (Exception ignored) {}
|
||||
return LocalDateTime.parse(cleaned, SLASH_FORMATTER);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 时区配置
|
||||
*/
|
||||
@Bean
|
||||
public Jackson2ObjectMapperBuilderCustomizer jacksonObjectMapperCustomization() {
|
||||
return builder -> {
|
||||
// 设置默认时区
|
||||
builder.timeZone(TimeZone.getDefault());
|
||||
// 设置日期格式为 yyyy/M/d HH:mm:ss,支持多种格式反序列化
|
||||
builder.simpleDateFormat("yyyy/M/d HH:mm:ss");
|
||||
// 添加JavaTimeModule支持,用于LocalDateTime
|
||||
JavaTimeModule javaTimeModule = new JavaTimeModule();
|
||||
javaTimeModule.addDeserializer(LocalDateTime.class, LOCAL_DATE_TIME_DESERIALIZER);
|
||||
builder.modules(javaTimeModule);
|
||||
builder.serializerByType(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy/M/d HH:mm:ss")));
|
||||
};
|
||||
public ObjectMapper objectMapper() {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
mapper.setTimeZone(TimeZone.getDefault());
|
||||
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
|
||||
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
|
||||
|
||||
JavaTimeModule javaTimeModule = new JavaTimeModule();
|
||||
javaTimeModule.addDeserializer(LocalDateTime.class, LOCAL_DATE_TIME_DESERIALIZER);
|
||||
javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||||
mapper.registerModule(javaTimeModule);
|
||||
|
||||
return mapper;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -72,8 +72,8 @@ public class StructuredEmrController {
|
||||
@GetMapping("/timeliness/statistics")
|
||||
@Operation(summary = "完成率统计")
|
||||
public R<Map<String, Object>> getCompletionStatistics(
|
||||
@RequestParam String startDate,
|
||||
@RequestParam String endDate) {
|
||||
@RequestParam(required = false) String startDate,
|
||||
@RequestParam(required = false) String endDate) {
|
||||
return R.ok(structuredEmrAppService.getCompletionStatistics(startDate, endDate));
|
||||
}
|
||||
|
||||
|
||||
@@ -99,4 +99,20 @@ public interface IInHospitalRegisterAppService {
|
||||
* @return 病区列表
|
||||
*/
|
||||
List<LocationDto> getWardList(Long orgId);
|
||||
|
||||
/**
|
||||
* 修改住院登记信息
|
||||
*
|
||||
* @param inHospitalInfoDto 登记dto
|
||||
* @return 结果
|
||||
*/
|
||||
R<?> updateRegistration(InHospitalInfoDto inHospitalInfoDto);
|
||||
|
||||
/**
|
||||
* 作废住院登记
|
||||
*
|
||||
* @param encounterId 住院就诊id
|
||||
* @return 结果
|
||||
*/
|
||||
R<?> voidRegistration(Long encounterId);
|
||||
}
|
||||
|
||||
@@ -84,6 +84,9 @@ public class InHospitalRegisterAppServiceImpl implements IInHospitalRegisterAppS
|
||||
@Resource
|
||||
private YbManager ybManager;
|
||||
|
||||
@Resource
|
||||
private IChargeItemService iChargeItemService;
|
||||
|
||||
/**
|
||||
* 门诊医生开住院申请
|
||||
*
|
||||
@@ -362,6 +365,183 @@ public class InHospitalRegisterAppServiceImpl implements IInHospitalRegisterAppS
|
||||
return locationDtoList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改住院登记信息
|
||||
*
|
||||
* @param inHospitalInfoDto 登记dto
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public R<?> updateRegistration(InHospitalInfoDto inHospitalInfoDto) {
|
||||
Long encounterId = inHospitalInfoDto.getEncounterId();
|
||||
if (encounterId == null) {
|
||||
throw new ServiceException("就诊ID不能为空");
|
||||
}
|
||||
Encounter encounter = iEncounterService.getById(encounterId);
|
||||
if (encounter == null) {
|
||||
throw new ServiceException("未找到该住院登记记录");
|
||||
}
|
||||
// 仅"待入科"状态可修改
|
||||
if (!EncounterZyStatus.REGISTERED.getValue().equals(encounter.getStatusEnum())) {
|
||||
throw new ServiceException("患者已入科接收,无法修改登记信息");
|
||||
}
|
||||
|
||||
// 更新就诊信息
|
||||
encounter.setOrganizationId(inHospitalInfoDto.getInHospitalOrgId()); // 住院科室
|
||||
encounter.setPriorityEnum(inHospitalInfoDto.getPriorityEnum()); // 优先级(患者病情)
|
||||
encounter.setAdmitSourceCode(inHospitalInfoDto.getAdmitSourceCode()); // 入院类型
|
||||
encounter.setInWayCode(inHospitalInfoDto.getInWayCode()); // 入院方式
|
||||
encounter.setStartTime(inHospitalInfoDto.getStartTime()); // 入院日期
|
||||
encounter.setRegistrarId(SecurityUtils.getLoginUser().getPractitionerId()); // 登记员
|
||||
iEncounterService.saveOrUpdate(encounter);
|
||||
|
||||
// 更新病区信息
|
||||
EncounterLocation encounterLocation = iEncounterLocationService.getOne(
|
||||
new LambdaQueryWrapper<EncounterLocation>()
|
||||
.eq(EncounterLocation::getEncounterId, encounterId)
|
||||
.eq(EncounterLocation::getFormEnum, LocationForm.WARD.getValue()));
|
||||
if (inHospitalInfoDto.getWardLocationId() != null) {
|
||||
EncounterLocation encounterLocationReg = new EncounterLocation();
|
||||
if (encounterLocation != null) {
|
||||
encounterLocationReg.setId(encounterLocation.getId());
|
||||
}
|
||||
encounterLocationReg.setEncounterId(encounterId);
|
||||
encounterLocationReg.setLocationId(inHospitalInfoDto.getWardLocationId());
|
||||
encounterLocationReg.setFormEnum(LocationForm.WARD.getValue());
|
||||
iEncounterLocationService.saveOrUpdate(encounterLocationReg);
|
||||
}
|
||||
|
||||
// 更新费用性质(contractNo)对应的账户信息
|
||||
if (inHospitalInfoDto.getContractNo() != null) {
|
||||
boolean selfFunded = CommonConstants.BusinessName.DEFAULT_CONTRACT_NO.equals(inHospitalInfoDto.getContractNo());
|
||||
|
||||
// 查找自费账户(type_code='04')
|
||||
Account cashAccount = iAccountService.getOne(
|
||||
new LambdaQueryWrapper<Account>()
|
||||
.eq(Account::getEncounterId, encounterId)
|
||||
.eq(Account::getTypeCode, AccountType.PERSONAL_CASH_ACCOUNT.getCode()));
|
||||
|
||||
// 查找非自费账户
|
||||
Account contractAccount = iAccountService.getOne(
|
||||
new LambdaQueryWrapper<Account>()
|
||||
.eq(Account::getEncounterId, encounterId)
|
||||
.ne(Account::getTypeCode, AccountType.PERSONAL_CASH_ACCOUNT.getCode()));
|
||||
|
||||
if (selfFunded) {
|
||||
// 改为自费
|
||||
if (cashAccount != null) {
|
||||
cashAccount.setContractNo(CommonConstants.BusinessName.DEFAULT_CONTRACT_NO);
|
||||
cashAccount.setEncounterFlag(Whether.YES.getValue());
|
||||
iAccountService.saveOrUpdate(cashAccount);
|
||||
} else {
|
||||
// 不存在自费账户时,创建一个
|
||||
Account newCashAccount = new Account();
|
||||
newCashAccount.setTypeCode(AccountType.PERSONAL_CASH_ACCOUNT.getCode());
|
||||
newCashAccount.setPatientId(encounter.getPatientId());
|
||||
newCashAccount.setEncounterId(encounterId);
|
||||
newCashAccount.setContractNo(CommonConstants.BusinessName.DEFAULT_CONTRACT_NO);
|
||||
newCashAccount.setEncounterFlag(Whether.YES.getValue());
|
||||
newCashAccount.setBalanceAmount(BigDecimal.ZERO);
|
||||
iAccountService.save(newCashAccount);
|
||||
}
|
||||
// 删除非自费账户
|
||||
if (contractAccount != null) {
|
||||
iAccountService.removeById(contractAccount.getId());
|
||||
}
|
||||
} else {
|
||||
// 改为非自费
|
||||
if (cashAccount != null) {
|
||||
cashAccount.setEncounterFlag(Whether.NO.getValue());
|
||||
iAccountService.saveOrUpdate(cashAccount);
|
||||
} else {
|
||||
// 不存在自费账户时,创建一个
|
||||
Account newCashAccount = new Account();
|
||||
newCashAccount.setTypeCode(AccountType.PERSONAL_CASH_ACCOUNT.getCode());
|
||||
newCashAccount.setPatientId(encounter.getPatientId());
|
||||
newCashAccount.setEncounterId(encounterId);
|
||||
newCashAccount.setContractNo(CommonConstants.BusinessName.DEFAULT_CONTRACT_NO);
|
||||
newCashAccount.setEncounterFlag(Whether.NO.getValue());
|
||||
newCashAccount.setBalanceAmount(BigDecimal.ZERO);
|
||||
iAccountService.save(newCashAccount);
|
||||
}
|
||||
// 更新或创建非自费账户
|
||||
String typeCode = StringUtils.isNotEmpty(inHospitalInfoDto.getTypeCoce())
|
||||
? inHospitalInfoDto.getTypeCoce()
|
||||
: AccountType.PERSONAL_CASH_ACCOUNT.getCode();
|
||||
if (contractAccount != null) {
|
||||
contractAccount.setContractNo(inHospitalInfoDto.getContractNo());
|
||||
iAccountService.saveOrUpdate(contractAccount);
|
||||
} else {
|
||||
Account newAccount = new Account();
|
||||
newAccount.setTypeCode(typeCode);
|
||||
newAccount.setPatientId(encounter.getPatientId());
|
||||
newAccount.setEncounterId(encounterId);
|
||||
newAccount.setContractNo(inHospitalInfoDto.getContractNo());
|
||||
newAccount.setEncounterFlag(Whether.YES.getValue());
|
||||
iAccountService.save(newAccount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00004, new Object[]{"住院登记"}));
|
||||
}
|
||||
|
||||
/**
|
||||
* 作废住院登记
|
||||
*
|
||||
* @param encounterId 住院就诊id
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public R<?> voidRegistration(Long encounterId) {
|
||||
if (encounterId == null) {
|
||||
throw new ServiceException("就诊ID不能为空");
|
||||
}
|
||||
Encounter encounter = iEncounterService.getById(encounterId);
|
||||
if (encounter == null) {
|
||||
throw new ServiceException("未找到该住院登记记录");
|
||||
}
|
||||
// 仅"待入科"状态可作废
|
||||
if (!EncounterZyStatus.REGISTERED.getValue().equals(encounter.getStatusEnum())) {
|
||||
throw new ServiceException("该患者已入科,请先通知护士站办理退科处理!");
|
||||
}
|
||||
|
||||
// 检查预交金余额
|
||||
Account cashAccount = iAccountService.getOne(
|
||||
new LambdaQueryWrapper<Account>()
|
||||
.eq(Account::getEncounterId, encounterId)
|
||||
.eq(Account::getTypeCode, AccountType.PERSONAL_CASH_ACCOUNT.getCode()));
|
||||
if (cashAccount != null && cashAccount.getBalanceAmount() != null
|
||||
&& cashAccount.getBalanceAmount().compareTo(BigDecimal.ZERO) > 0) {
|
||||
throw new ServiceException("该患者存在未退清的预交金,请先前往预交金页面办理退款!");
|
||||
}
|
||||
|
||||
// 检查是否已产生计费
|
||||
long chargeCount = iChargeItemService.count(
|
||||
new LambdaQueryWrapper<ChargeItem>()
|
||||
.eq(ChargeItem::getEncounterId, encounterId));
|
||||
if (chargeCount > 0) {
|
||||
throw new ServiceException("该患者已产生计费记录,无法作废登记!");
|
||||
}
|
||||
|
||||
// 设置状态为已作废
|
||||
encounter.setStatusEnum(EncounterZyStatus.VOIDED.getValue());
|
||||
encounter.setRegistrarId(SecurityUtils.getLoginUser().getPractitionerId()); // 作废操作人
|
||||
iEncounterService.saveOrUpdate(encounter);
|
||||
|
||||
// 清理账户记录
|
||||
if (cashAccount != null) {
|
||||
iAccountService.removeById(cashAccount.getId());
|
||||
}
|
||||
// 清理非自费账户
|
||||
iAccountService.remove(
|
||||
new LambdaQueryWrapper<Account>()
|
||||
.eq(Account::getEncounterId, encounterId)
|
||||
.ne(Account::getTypeCode, AccountType.PERSONAL_CASH_ACCOUNT.getCode()));
|
||||
|
||||
return R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00004, new Object[]{"作废操作"}));
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理入院登记信息
|
||||
*
|
||||
|
||||
@@ -142,4 +142,26 @@ public class InHospitalRegisterController {
|
||||
return R.ok(iInHospitalRegisterAppService.getWardList(orgId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改住院登记信息
|
||||
*
|
||||
* @param inHospitalInfoDto 登记dto
|
||||
* @return 结果
|
||||
*/
|
||||
@PutMapping(value = "/update-registration")
|
||||
public R<?> updateRegistration(@RequestBody InHospitalInfoDto inHospitalInfoDto) {
|
||||
return iInHospitalRegisterAppService.updateRegistration(inHospitalInfoDto);
|
||||
}
|
||||
|
||||
/**
|
||||
* 作废住院登记
|
||||
*
|
||||
* @param encounterId 住院就诊id
|
||||
* @return 结果
|
||||
*/
|
||||
@PutMapping(value = "/void-registration")
|
||||
public R<?> voidRegistration(@RequestParam(value = "encounterId") Long encounterId) {
|
||||
return iInHospitalRegisterAppService.voidRegistration(encounterId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -95,4 +95,9 @@ public class InHospitalRegisterQueryDto {
|
||||
private String admitSourceCode;
|
||||
private String admitSourceCode_dictText;
|
||||
|
||||
/**
|
||||
* 住院状态
|
||||
*/
|
||||
private Integer statusEnum;
|
||||
|
||||
}
|
||||
|
||||
@@ -186,13 +186,18 @@ public class AdviceProcessAppServiceImpl implements IAdviceProcessAppService {
|
||||
QueryWrapper<InpatientAdviceParam> queryWrapper
|
||||
= HisQueryUtils.buildQueryWrapper(inpatientAdviceParam, null, null, null);
|
||||
|
||||
// 手动拼接requestStatus条件:COMPLETED(3)时同时包含CHECK_VERIFIED(10)和PENDING_RECEIVE(11)
|
||||
// 手动拼接requestStatus条件
|
||||
// COMPLETED(3)时同时包含CHECK_VERIFIED(10)和PENDING_RECEIVE(11)
|
||||
// ACTIVE(2)时同时包含PENDING_STOP(13),以便护士核对停嘱医嘱
|
||||
// UNION查询外层列名为request_status(T1.status_enum AS request_status),不是status_enum
|
||||
if (requestStatus != null) {
|
||||
if (RequestStatus.COMPLETED.getValue().equals(requestStatus)) {
|
||||
queryWrapper.in("request_status",
|
||||
RequestStatus.COMPLETED.getValue(), RequestStatus.CHECK_VERIFIED.getValue(),
|
||||
RequestStatus.PENDING_RECEIVE.getValue());
|
||||
} else if (RequestStatus.ACTIVE.getValue().equals(requestStatus)) {
|
||||
queryWrapper.in("request_status",
|
||||
RequestStatus.ACTIVE.getValue(), RequestStatus.PENDING_STOP.getValue());
|
||||
} else {
|
||||
queryWrapper.eq("request_status", requestStatus);
|
||||
}
|
||||
@@ -230,6 +235,70 @@ public class AdviceProcessAppServiceImpl implements IAdviceProcessAppService {
|
||||
if (e.getBirthDate() != null) {
|
||||
e.setAge(AgeCalculatorUtil.getAge(e.getBirthDate()));
|
||||
}
|
||||
|
||||
// ---------- Bug #595: 医嘱校对列表计算字段 ----------
|
||||
|
||||
// 单次剂量:剂量 + 单位
|
||||
if (e.getDose() != null) {
|
||||
String doseStr = e.getDose().stripTrailingZeros().toPlainString();
|
||||
String unitStr = e.getDoseUnitCode_dictText() != null ? e.getDoseUnitCode_dictText() : "";
|
||||
e.setSingleDose(doseStr + unitStr);
|
||||
}
|
||||
|
||||
// 总量:剂量 × 数量 + 单位(仅药品医嘱)
|
||||
if (e.getDose() != null && e.getQuantity() != null) {
|
||||
BigDecimal total = e.getDose().multiply(BigDecimal.valueOf(e.getQuantity()));
|
||||
String totalStr = total.stripTrailingZeros().toPlainString();
|
||||
String unitStr = e.getUnitCode_dictText() != null ? e.getUnitCode_dictText() : "";
|
||||
e.setTotalAmount(totalStr + unitStr);
|
||||
} else if (e.getQuantity() != null) {
|
||||
String unitStr = e.getUnitCode_dictText() != null ? e.getUnitCode_dictText() : "";
|
||||
e.setTotalAmount(e.getQuantity() + unitStr);
|
||||
}
|
||||
|
||||
// 频次/用法组合(直接使用DictUtils翻译,避免DictAspect延迟导致_dictText为空)
|
||||
String rateLabel = e.getRateCode() != null ? DictUtils.getDictLabel("rate_code", e.getRateCode()) : null;
|
||||
String methodLabel = e.getMethodCode() != null ? DictUtils.getDictLabel("method_code", e.getMethodCode()) : null;
|
||||
StringBuilder freqBuilder = new StringBuilder();
|
||||
if (rateLabel != null && !rateLabel.isEmpty()) {
|
||||
freqBuilder.append(rateLabel);
|
||||
}
|
||||
if (methodLabel != null && !methodLabel.isEmpty()) {
|
||||
if (freqBuilder.length() > 0) freqBuilder.append(" ");
|
||||
freqBuilder.append(methodLabel);
|
||||
}
|
||||
e.setFrequencyUsage(freqBuilder.length() > 0 ? freqBuilder.toString() : null);
|
||||
|
||||
// 开嘱医生
|
||||
e.setOrderingDoctor(e.getRequesterId_dictText() != null
|
||||
? e.getRequesterId_dictText() : e.getAdmittingDoctorName());
|
||||
|
||||
// 皮试状态 + 高亮
|
||||
if (e.getSkinTestFlag() != null && e.getSkinTestFlag() == 1) {
|
||||
e.setSkinTestStatus("需皮试");
|
||||
e.setSkinTestHighlight(true);
|
||||
} else if (e.getSkinTestFlag() != null && e.getSkinTestFlag() == 2) {
|
||||
e.setSkinTestStatus("皮试通过");
|
||||
e.setSkinTestHighlight(false);
|
||||
} else {
|
||||
e.setSkinTestStatus("无需");
|
||||
e.setSkinTestHighlight(false);
|
||||
}
|
||||
|
||||
// 注射药品标记
|
||||
e.setIsInjection(e.getInjectFlag() != null && e.getInjectFlag() == 1);
|
||||
|
||||
// 停嘱医生
|
||||
e.setStopperName(e.getStopperName());
|
||||
|
||||
// 停嘱时间
|
||||
e.setStopTime(e.getEndTime());
|
||||
|
||||
// 医嘱号
|
||||
e.setOrderNo(e.getRequestId() != null ? e.getRequestId().toString() : null);
|
||||
|
||||
// 诊断(行级)
|
||||
e.setDiagnosis(e.getConditionNames());
|
||||
});
|
||||
|
||||
// 获取医嘱列表
|
||||
@@ -333,10 +402,29 @@ public class AdviceProcessAppServiceImpl implements IAdviceProcessAppService {
|
||||
List<Long> serviceReqIds = serviceRequestList.stream().map(PerformInfoDto::getRequestId).toList();
|
||||
// 先查询服务请求,按 categoryEnum 分流:检查类(23)走 CHECK_VERIFIED,其余走 COMPLETED
|
||||
List<ServiceRequest> allServiceRequests = serviceRequestService.listByIds(serviceReqIds);
|
||||
List<Long> checkReqIds = allServiceRequests.stream()
|
||||
|
||||
// 分离已停嘱(PENDING_STOP)的订单,护士核对后变为已停止(STOPPED)
|
||||
List<ServiceRequest> pendingStopRequests = allServiceRequests.stream()
|
||||
.filter(sr -> RequestStatus.PENDING_STOP.getValue().equals(sr.getStatusEnum()))
|
||||
.toList();
|
||||
List<ServiceRequest> normalRequests = allServiceRequests.stream()
|
||||
.filter(sr -> !RequestStatus.PENDING_STOP.getValue().equals(sr.getStatusEnum()))
|
||||
.toList();
|
||||
|
||||
// 已停嘱订单 → 已停止(STOPPED)
|
||||
if (!pendingStopRequests.isEmpty()) {
|
||||
List<Long> pendingStopIds = pendingStopRequests.stream().map(ServiceRequest::getId).toList();
|
||||
serviceRequestService.update(new LambdaUpdateWrapper<ServiceRequest>()
|
||||
.in(ServiceRequest::getId, pendingStopIds)
|
||||
.set(ServiceRequest::getStatusEnum, RequestStatus.STOPPED.getValue())
|
||||
.set(ServiceRequest::getUpdateBy, SecurityUtils.getNickName()));
|
||||
}
|
||||
|
||||
// 正常订单:检查类 → 已校对(CHECK_VERIFIED=10),其余 → 已完成(COMPLETED=3)
|
||||
List<Long> checkReqIds = normalRequests.stream()
|
||||
.filter(sr -> ActivityDefCategory.TEST.getValue().equals(sr.getCategoryEnum()))
|
||||
.map(ServiceRequest::getId).toList();
|
||||
List<Long> otherReqIds = allServiceRequests.stream()
|
||||
List<Long> otherReqIds = normalRequests.stream()
|
||||
.filter(sr -> !ActivityDefCategory.TEST.getValue().equals(sr.getCategoryEnum()))
|
||||
.map(ServiceRequest::getId).toList();
|
||||
// 检查类 → 已校对(CHECK_VERIFIED=10)
|
||||
@@ -348,7 +436,7 @@ public class AdviceProcessAppServiceImpl implements IAdviceProcessAppService {
|
||||
serviceRequestService.updateCompleteRequestStatus(otherReqIds, practitionerId, checkDate);
|
||||
}
|
||||
// 处理转科/出院等特殊医嘱
|
||||
for (ServiceRequest serviceRequest : allServiceRequests) {
|
||||
for (ServiceRequest serviceRequest : normalRequests) {
|
||||
if (ActivityDefCategory.TRANSFER.getValue().equals(serviceRequest.getCategoryEnum())) {
|
||||
encounterService.updateEncounterStatus(serviceRequest.getEncounterId(),
|
||||
EncounterZyStatus.PENDING_TRANSFER.getValue());
|
||||
@@ -359,9 +447,30 @@ public class AdviceProcessAppServiceImpl implements IAdviceProcessAppService {
|
||||
}
|
||||
}
|
||||
if (!medRequestList.isEmpty()) {
|
||||
// 更新药品请求状态已完成
|
||||
medicationRequestService.updateCompletedStatusBatch(
|
||||
medRequestList.stream().map(PerformInfoDto::getRequestId).toList(), practitionerId, checkDate);
|
||||
List<Long> medReqIds = medRequestList.stream().map(PerformInfoDto::getRequestId).toList();
|
||||
// 查询药品请求,分离已停嘱(PENDING_STOP)的订单
|
||||
List<MedicationRequest> allMedRequests = medicationRequestService.list(
|
||||
new LambdaQueryWrapper<MedicationRequest>()
|
||||
.select(MedicationRequest::getId, MedicationRequest::getStatusEnum)
|
||||
.in(MedicationRequest::getId, medReqIds));
|
||||
List<Long> pendingStopMedIds = allMedRequests.stream()
|
||||
.filter(mr -> RequestStatus.PENDING_STOP.getValue().equals(mr.getStatusEnum()))
|
||||
.map(MedicationRequest::getId).toList();
|
||||
List<Long> normalMedIds = allMedRequests.stream()
|
||||
.filter(mr -> !RequestStatus.PENDING_STOP.getValue().equals(mr.getStatusEnum()))
|
||||
.map(MedicationRequest::getId).toList();
|
||||
|
||||
// 已停嘱订单 → 已停止(STOPPED)
|
||||
if (!pendingStopMedIds.isEmpty()) {
|
||||
medicationRequestService.update(new LambdaUpdateWrapper<MedicationRequest>()
|
||||
.in(MedicationRequest::getId, pendingStopMedIds)
|
||||
.set(MedicationRequest::getStatusEnum, RequestStatus.STOPPED.getValue())
|
||||
.set(MedicationRequest::getUpdateBy, SecurityUtils.getNickName()));
|
||||
}
|
||||
// 正常订单 → 已完成(COMPLETED)
|
||||
if (!normalMedIds.isEmpty()) {
|
||||
medicationRequestService.updateCompletedStatusBatch(normalMedIds, practitionerId, checkDate);
|
||||
}
|
||||
}
|
||||
return R.ok(null, "校对成功");
|
||||
}
|
||||
|
||||
@@ -190,8 +190,9 @@ public class MedicineSummaryAppServiceImpl implements IMedicineSummaryAppService
|
||||
}
|
||||
// 领药人
|
||||
Long receiverId = medicineSummaryParamList.get(0).getReceiverId();
|
||||
// 申请时间
|
||||
Date now = DateUtils.getNowDate();
|
||||
// 申请时间(优先使用前端传递的操作时间,确保与实际操作时间一致)
|
||||
Date now = medicineSummaryParamList.get(0).getDispenseTime() != null
|
||||
? medicineSummaryParamList.get(0).getDispenseTime() : DateUtils.getNowDate();
|
||||
// 申请人
|
||||
Long practitionerId = SecurityUtils.getLoginUser().getPractitionerId();
|
||||
// 药品发放id
|
||||
|
||||
@@ -259,4 +259,40 @@ public class InpatientAdviceDto {
|
||||
/** 发药状态 */
|
||||
private Integer dispenseStatus;
|
||||
private String dispenseStatus_enumText;
|
||||
|
||||
// ========== Bug #595 计算展示字段 ==========
|
||||
|
||||
/** 单次剂量(格式化:剂量+单位) */
|
||||
private String singleDose;
|
||||
|
||||
/** 总量(格式化:剂量×数量+单位) */
|
||||
private String totalAmount;
|
||||
|
||||
/** 频次/用法组合(如:tid 静滴) */
|
||||
private String frequencyUsage;
|
||||
|
||||
/** 开嘱医生 */
|
||||
private String orderingDoctor;
|
||||
|
||||
/** 皮试状态文本(需皮试/皮试通过/无需) */
|
||||
private String skinTestStatus;
|
||||
|
||||
/** 皮试高亮标记(需皮试时为true) */
|
||||
private Boolean skinTestHighlight;
|
||||
|
||||
/** 是否注射药品 */
|
||||
private Boolean isInjection;
|
||||
|
||||
/** 停嘱医生 */
|
||||
private String stopperName;
|
||||
|
||||
/** 停嘱时间 */
|
||||
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date stopTime;
|
||||
|
||||
/** 医嘱号 */
|
||||
private String orderNo;
|
||||
|
||||
/** 诊断(行级展示) */
|
||||
private String diagnosis;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,8 @@ import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
@@ -310,13 +312,73 @@ public class PatientInformationServiceImpl implements IPatientInformationService
|
||||
patient.setBloodAbo(patientInfoDto.getBloodAbo()); // 血型ABO
|
||||
patient.setBloodRh(patientInfoDto.getBloodRh()); // 血型RH
|
||||
patient.setMaritalStatusEnum(patientInfoDto.getMaritalStatusEnum()); // 婚姻状态
|
||||
patient.setDeceasedDate(patientInfoDto.getDeceasedDate()); // 死亡时间
|
||||
// 死亡时间:支持 yyyy-MM-dd HH:mm:ss 和 yyyy/MM/dd HH:mm:ss 格式
|
||||
if (patientInfoDto.getDeceasedDate() != null && !patientInfoDto.getDeceasedDate().isEmpty()) {
|
||||
String dateStr = patientInfoDto.getDeceasedDate();
|
||||
String[] patterns = {"yyyy-MM-dd HH:mm:ss", "yyyy/MM/dd HH:mm:ss", "yyyy/M/d HH:mm:ss"};
|
||||
Date parsedDate = null;
|
||||
for (String pat : patterns) {
|
||||
try { parsedDate = new SimpleDateFormat(pat).parse(dateStr); break; } catch (Exception ignored) {}
|
||||
}
|
||||
patient.setDeceasedDate(parsedDate);
|
||||
} else {
|
||||
patient.setDeceasedDate(null);
|
||||
}
|
||||
patient.setNationalityCode(patientInfoDto.getNationalityCode());// 民族
|
||||
patient.setActiveFlag(patientInfoDto.getActiveFlag());// 活动标识
|
||||
patient.setCountryCode(patientInfoDto.getCountryCode());// 国家编码
|
||||
patient.setPostalCode(patientInfoDto.getPostalCode());// 邮政编码
|
||||
patient.setHukouAddress(patientInfoDto.getHukouAddress());// 户籍地址
|
||||
patient.setGuardianName(patientInfoDto.getGuardianName());// 监护人姓名
|
||||
patient.setGuardianRelation(patientInfoDto.getGuardianRelation());// 监护人关系
|
||||
patient.setGuardianPhone(patientInfoDto.getGuardianPhone());// 监护人电话
|
||||
patient.setGuardianIdType(patientInfoDto.getGuardianIdType());// 监护人证件类型
|
||||
patient.setGuardianIdNo(patientInfoDto.getGuardianIdNo());// 监护人证件号码
|
||||
patient.setGuardianAddress(patientInfoDto.getGuardianAddress());// 监护人地址
|
||||
patient.setPatientDerived(patientInfoDto.getPatientDerived());// 患者来源
|
||||
patient.setEducationLevel(patientInfoDto.getEducationLevel());// 文化程度
|
||||
patient.setCompanyAddress(patientInfoDto.getCompanyAddress());// 单位地址
|
||||
|
||||
if (patientInfoDto.getId() != null) {
|
||||
// 更新操作
|
||||
patientService.updateById(patient);
|
||||
// 更新操作 - 使用 LambdaUpdateWrapper 显式设置所有字段,确保 null 值也能正确更新
|
||||
LambdaUpdateWrapper<Patient> updateWrapper = new LambdaUpdateWrapper<>();
|
||||
updateWrapper.eq(Patient::getId, patient.getId())
|
||||
.set(Patient::getName, patient.getName())
|
||||
.set(Patient::getPyStr, patient.getPyStr())
|
||||
.set(Patient::getWbStr, patient.getWbStr())
|
||||
.set(Patient::getIdCard, patient.getIdCard())
|
||||
.set(Patient::getBirthDate, patient.getBirthDate())
|
||||
.set(Patient::getGenderEnum, patient.getGenderEnum())
|
||||
.set(Patient::getPhone, patient.getPhone())
|
||||
.set(Patient::getPrfsEnum, patient.getPrfsEnum())
|
||||
.set(Patient::getWorkCompany, patient.getWorkCompany())
|
||||
.set(Patient::getLinkName, patient.getLinkName())
|
||||
.set(Patient::getLinkRelationCode, patient.getLinkRelationCode())
|
||||
.set(Patient::getLinkTelcom, patient.getLinkTelcom())
|
||||
.set(Patient::getAddress, patient.getAddress())
|
||||
.set(Patient::getAddressProvince, patient.getAddressProvince())
|
||||
.set(Patient::getAddressCity, patient.getAddressCity())
|
||||
.set(Patient::getAddressDistrict, patient.getAddressDistrict())
|
||||
.set(Patient::getAddressStreet, patient.getAddressStreet())
|
||||
.set(Patient::getBloodAbo, patient.getBloodAbo())
|
||||
.set(Patient::getBloodRh, patient.getBloodRh())
|
||||
.set(Patient::getMaritalStatusEnum, patient.getMaritalStatusEnum())
|
||||
.set(Patient::getDeceasedDate, patient.getDeceasedDate())
|
||||
.set(Patient::getNationalityCode, patient.getNationalityCode())
|
||||
.set(Patient::getActiveFlag, patient.getActiveFlag())
|
||||
.set(Patient::getCountryCode, patient.getCountryCode())
|
||||
.set(Patient::getPostalCode, patient.getPostalCode())
|
||||
.set(Patient::getHukouAddress, patient.getHukouAddress())
|
||||
.set(Patient::getGuardianName, patient.getGuardianName())
|
||||
.set(Patient::getGuardianRelation, patient.getGuardianRelation())
|
||||
.set(Patient::getGuardianPhone, patient.getGuardianPhone())
|
||||
.set(Patient::getGuardianIdType, patient.getGuardianIdType())
|
||||
.set(Patient::getGuardianIdNo, patient.getGuardianIdNo())
|
||||
.set(Patient::getGuardianAddress, patient.getGuardianAddress())
|
||||
.set(Patient::getPatientDerived, patient.getPatientDerived())
|
||||
.set(Patient::getEducationLevel, patient.getEducationLevel())
|
||||
.set(Patient::getCompanyAddress, patient.getCompanyAddress());
|
||||
patientService.update(updateWrapper);
|
||||
} else {
|
||||
// 新增操作
|
||||
patientService.save(patient);
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.healthlink.his.web.patientmanage.dto;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 支持多种日期格式的反序列化器
|
||||
* 兼容 yyyy-MM-dd HH:mm:ss 和 yyyy/MM/dd HH:mm:ss 等格式
|
||||
*/
|
||||
public class FlexibleDateDeserializer extends JsonDeserializer<Date> {
|
||||
|
||||
private static final String[] DATE_FORMATS = {
|
||||
"yyyy-MM-dd HH:mm:ss",
|
||||
"yyyy/MM/dd HH:mm:ss",
|
||||
"yyyy/M/d HH:mm:ss",
|
||||
"yyyy-MM-dd'T'HH:mm:ss",
|
||||
"yyyy-MM-dd'T'HH:mm:ss.SSS",
|
||||
"yyyy-MM-dd",
|
||||
"yyyy/MM/dd"
|
||||
};
|
||||
|
||||
@Override
|
||||
public Date deserialize(JsonParser p, DeserializationContext context) throws IOException {
|
||||
String dateStr = p.getValueAsString();
|
||||
if (dateStr == null || dateStr.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
for (String pattern : DATE_FORMATS) {
|
||||
try {
|
||||
return new SimpleDateFormat(pattern).parse(dateStr);
|
||||
} catch (ParseException ignored) {
|
||||
}
|
||||
}
|
||||
throw new IOException("无法解析日期: " + dateStr + ",支持格式: yyyy-MM-dd HH:mm:ss 或 yyyy/MM/dd HH:mm:ss");
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.healthlink.his.web.patientmanage.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import com.healthlink.his.common.annotation.Dict;
|
||||
@@ -144,8 +145,7 @@ public class PatientBaseInfoDto {
|
||||
/**
|
||||
* 死亡时间
|
||||
*/
|
||||
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date deceasedDate;
|
||||
private String deceasedDate;
|
||||
|
||||
/**
|
||||
* 病人证件信息集合
|
||||
@@ -168,4 +168,65 @@ public class PatientBaseInfoDto {
|
||||
*/
|
||||
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 邮政编码
|
||||
*/
|
||||
private String postalCode;
|
||||
|
||||
/**
|
||||
* 户籍地址
|
||||
*/
|
||||
private String hukouAddress;
|
||||
|
||||
/**
|
||||
* 监护人姓名
|
||||
*/
|
||||
private String guardianName;
|
||||
|
||||
/**
|
||||
* 监护人关系
|
||||
*/
|
||||
private Integer guardianRelation;
|
||||
private String guardianRelation_enumText;
|
||||
|
||||
/**
|
||||
* 监护人电话
|
||||
*/
|
||||
private String guardianPhone;
|
||||
|
||||
/**
|
||||
* 监护人证件类型
|
||||
*/
|
||||
private String guardianIdType;
|
||||
|
||||
/**
|
||||
* 监护人证件号码
|
||||
*/
|
||||
private String guardianIdNo;
|
||||
|
||||
/**
|
||||
* 监护人地址
|
||||
*/
|
||||
private String guardianAddress;
|
||||
|
||||
/**
|
||||
* 患者来源
|
||||
*/
|
||||
private String patientDerived;
|
||||
|
||||
/**
|
||||
* 文化程度
|
||||
*/
|
||||
private String educationLevel;
|
||||
|
||||
/**
|
||||
* 单位地址
|
||||
*/
|
||||
private String companyAddress;
|
||||
|
||||
/**
|
||||
* 国家编码
|
||||
*/
|
||||
private String countryCode;
|
||||
}
|
||||
|
||||
@@ -155,6 +155,8 @@ public class WesternMedicineDispenseAppServiceImpl implements IWesternMedicineDi
|
||||
|
||||
// 发药状态
|
||||
List<DispenseStatusOption> dispenseStatusOptions = new ArrayList<>();
|
||||
dispenseStatusOptions.add(new DispenseStatusOption(DispenseStatus.SUBMITTED.getValue(),
|
||||
DispenseStatus.SUBMITTED.getInfo()));
|
||||
dispenseStatusOptions.add(new DispenseStatusOption(DispenseStatus.IN_PROGRESS.getValue(),
|
||||
DispenseStatus.IN_PROGRESS.getInfo()));
|
||||
dispenseStatusOptions.add(new DispenseStatusOption(DispenseStatus.COMPLETED.getValue(),
|
||||
|
||||
@@ -4,6 +4,10 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.core.common.core.domain.R;
|
||||
import com.healthlink.his.reconstruction.domain.*;
|
||||
import com.healthlink.his.reconstruction.service.*;
|
||||
import com.core.system.service.ISysUserService;
|
||||
import com.core.system.service.ISysRoleService;
|
||||
import com.core.common.core.domain.entity.SysRole;
|
||||
import com.core.common.core.domain.entity.SysUser;
|
||||
import lombok.AllArgsConstructor;import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;import org.springframework.web.bind.annotation.*;
|
||||
@@ -13,6 +17,8 @@ public class Reconstruction3DController {
|
||||
private final IReconstructionTaskService taskService;
|
||||
private final IReconstructionResultService resultService;
|
||||
private final IReconstructionReportService reportService;
|
||||
private final ISysUserService userService;
|
||||
private final ISysRoleService roleService;
|
||||
|
||||
// ==================== 重建任务 ====================
|
||||
@GetMapping("/task/page")
|
||||
@@ -100,4 +106,32 @@ public class Reconstruction3DController {
|
||||
stats.put("totalReports", reportService.count());
|
||||
return R.ok(stats);
|
||||
}
|
||||
|
||||
// ==================== 医生列表 ====================
|
||||
@GetMapping("/doctors")
|
||||
public R<?> getDoctors() {
|
||||
SysUser query = new SysUser();
|
||||
query.setStatus("0");
|
||||
query.setDelFlag("0");
|
||||
List<SysUser> allUsers = userService.selectUserList(query);
|
||||
// For each user, check if they have role 200 (doctor)
|
||||
List<Map<String, Object>> doctors = new ArrayList<>();
|
||||
for (SysUser user : allUsers) {
|
||||
List<SysRole> roles = roleService.selectRolesByUserId(user.getUserId());
|
||||
if (roles != null) {
|
||||
for (SysRole role : roles) {
|
||||
if (role.getRoleId() != null && role.getRoleId() == 200L) {
|
||||
Map<String, Object> doc = new HashMap<>();
|
||||
doc.put("userId", user.getUserId());
|
||||
doc.put("userName", user.getUserName());
|
||||
doc.put("nickName", user.getNickName());
|
||||
doctors.add(doc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return R.ok(doctors);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1122,14 +1122,14 @@ public class AdviceManageAppServiceImpl implements IAdviceManageAppService {
|
||||
iMedicationRequestService.update(new LambdaUpdateWrapper<MedicationRequest>()
|
||||
.in(MedicationRequest::getId, medicineRequestIds)
|
||||
.set(MedicationRequest::getEffectiveDoseEnd, stopTime)
|
||||
.set(MedicationRequest::getStatusEnum, RequestStatus.STOPPED.getValue())
|
||||
.set(MedicationRequest::getStatusEnum, RequestStatus.PENDING_STOP.getValue())
|
||||
.set(MedicationRequest::getUpdateBy, stopUserName));
|
||||
}
|
||||
if (!activityRequestIds.isEmpty()) {
|
||||
iServiceRequestService.update(new LambdaUpdateWrapper<ServiceRequest>()
|
||||
.in(ServiceRequest::getId, activityRequestIds)
|
||||
.set(ServiceRequest::getOccurrenceEndTime, stopTime)
|
||||
.set(ServiceRequest::getStatusEnum, RequestStatus.STOPPED.getValue())
|
||||
.set(ServiceRequest::getStatusEnum, RequestStatus.PENDING_STOP.getValue())
|
||||
.set(ServiceRequest::getUpdateBy, stopUserName));
|
||||
}
|
||||
return R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00004, new Object[]{"医嘱停止"}));
|
||||
@@ -1173,7 +1173,8 @@ public class AdviceManageAppServiceImpl implements IAdviceManageAppService {
|
||||
.select(MedicationRequest::getId, MedicationRequest::getStatusEnum)
|
||||
.in(MedicationRequest::getId, medicineRequestIds));
|
||||
for (MedicationRequest mr : medicineRequestList) {
|
||||
if (!RequestStatus.STOPPED.getValue().equals(mr.getStatusEnum())) {
|
||||
if (!RequestStatus.STOPPED.getValue().equals(mr.getStatusEnum())
|
||||
&& !RequestStatus.PENDING_STOP.getValue().equals(mr.getStatusEnum())) {
|
||||
throw new ServiceException("护士站已确认停止该医嘱,无法取消停嘱!");
|
||||
}
|
||||
}
|
||||
@@ -1184,7 +1185,8 @@ public class AdviceManageAppServiceImpl implements IAdviceManageAppService {
|
||||
.select(ServiceRequest::getId, ServiceRequest::getStatusEnum)
|
||||
.in(ServiceRequest::getId, activityRequestIds));
|
||||
for (ServiceRequest sr : activityRequestList) {
|
||||
if (!RequestStatus.STOPPED.getValue().equals(sr.getStatusEnum())) {
|
||||
if (!RequestStatus.STOPPED.getValue().equals(sr.getStatusEnum())
|
||||
&& !RequestStatus.PENDING_STOP.getValue().equals(sr.getStatusEnum())) {
|
||||
throw new ServiceException("护士站已确认停止该医嘱,无法取消停嘱!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
-- Bug #705: 患者管理修改后字段回显丢失修复
|
||||
-- 添加邮政编码、户籍地址、监护人信息、患者来源等缺失字段到adm_patient表
|
||||
|
||||
-- 邮政编码
|
||||
ALTER TABLE adm_patient ADD COLUMN IF NOT EXISTS postal_code VARCHAR(10);
|
||||
|
||||
-- 户籍地址
|
||||
ALTER TABLE adm_patient ADD COLUMN IF NOT EXISTS hukou_address VARCHAR(500);
|
||||
|
||||
-- 监护人信息
|
||||
ALTER TABLE adm_patient ADD COLUMN IF NOT EXISTS guardian_name VARCHAR(50);
|
||||
ALTER TABLE adm_patient ADD COLUMN IF NOT EXISTS guardian_relation INTEGER;
|
||||
ALTER TABLE adm_patient ADD COLUMN IF NOT EXISTS guardian_phone VARCHAR(20);
|
||||
ALTER TABLE adm_patient ADD COLUMN IF NOT EXISTS guardian_id_type VARCHAR(10);
|
||||
ALTER TABLE adm_patient ADD COLUMN IF NOT EXISTS guardian_id_no VARCHAR(30);
|
||||
ALTER TABLE adm_patient ADD COLUMN IF NOT EXISTS guardian_address VARCHAR(500);
|
||||
|
||||
-- 患者来源
|
||||
ALTER TABLE adm_patient ADD COLUMN IF NOT EXISTS patient_derived VARCHAR(50);
|
||||
|
||||
-- 文化程度
|
||||
ALTER TABLE adm_patient ADD COLUMN IF NOT EXISTS education_level VARCHAR(20);
|
||||
|
||||
-- 单位地址
|
||||
ALTER TABLE adm_patient ADD COLUMN IF NOT EXISTS company_address VARCHAR(500);
|
||||
@@ -0,0 +1,79 @@
|
||||
-- V40: 修复EMR模块数据库表结构问题
|
||||
-- 1. emr_archive_record表:添加缺失的审计字段,修复NOT NULL约束
|
||||
-- 2. emr_search_index表:修复NOT NULL约束
|
||||
-- 3. emr_revision表:添加缺失的审计字段
|
||||
|
||||
-- ==========================================
|
||||
-- 1. emr_archive_record 表修复
|
||||
-- ==========================================
|
||||
|
||||
-- 添加缺失的审计字段(如果不存在)
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'emr_archive_record' AND column_name = 'create_by') THEN
|
||||
ALTER TABLE emr_archive_record ADD COLUMN create_by character varying;
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'emr_archive_record' AND column_name = 'update_by') THEN
|
||||
ALTER TABLE emr_archive_record ADD COLUMN update_by character varying;
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'emr_archive_record' AND column_name = 'update_time') THEN
|
||||
ALTER TABLE emr_archive_record ADD COLUMN update_time timestamp without time zone;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- 修复NOT NULL约束
|
||||
ALTER TABLE emr_archive_record ALTER COLUMN emr_id DROP NOT NULL;
|
||||
ALTER TABLE emr_archive_record ALTER COLUMN patient_id DROP NOT NULL;
|
||||
ALTER TABLE emr_archive_record ALTER COLUMN archive_type DROP NOT NULL;
|
||||
|
||||
-- ==========================================
|
||||
-- 2. emr_search_index 表修复
|
||||
-- ==========================================
|
||||
|
||||
-- 修复NOT NULL约束
|
||||
ALTER TABLE emr_search_index ALTER COLUMN emr_id DROP NOT NULL;
|
||||
ALTER TABLE emr_search_index ALTER COLUMN encounter_id DROP NOT NULL;
|
||||
ALTER TABLE emr_search_index ALTER COLUMN patient_id DROP NOT NULL;
|
||||
|
||||
-- ==========================================
|
||||
-- 3. emr_revision 表修复
|
||||
-- ==========================================
|
||||
|
||||
-- 添加缺失的审计字段
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'emr_revision' AND column_name = 'create_by') THEN
|
||||
ALTER TABLE emr_revision ADD COLUMN create_by character varying;
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'emr_revision' AND column_name = 'tenant_id') THEN
|
||||
ALTER TABLE emr_revision ADD COLUMN tenant_id bigint;
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'emr_revision' AND column_name = 'update_by') THEN
|
||||
ALTER TABLE emr_revision ADD COLUMN update_by character varying;
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'emr_revision' AND column_name = 'update_time') THEN
|
||||
ALTER TABLE emr_revision ADD COLUMN update_time timestamp without time zone;
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'emr_revision' AND column_name = 'delete_flag') THEN
|
||||
ALTER TABLE emr_revision ADD COLUMN delete_flag character varying;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- ==========================================
|
||||
-- 4. 添加索引以优化查询性能
|
||||
-- ==========================================
|
||||
|
||||
-- emr_archive_record 索引
|
||||
CREATE INDEX IF NOT EXISTS idx_emr_archive_patient_name ON emr_archive_record(patient_name);
|
||||
CREATE INDEX IF NOT EXISTS idx_emr_archive_status ON emr_archive_record(archive_status);
|
||||
CREATE INDEX IF NOT EXISTS idx_emr_archive_encounter ON emr_archive_record(encounter_id);
|
||||
|
||||
-- emr_search_index 索引
|
||||
CREATE INDEX IF NOT EXISTS idx_emr_search_patient ON emr_search_index(patient_name);
|
||||
CREATE INDEX IF NOT EXISTS idx_emr_search_type ON emr_search_index(emr_type);
|
||||
CREATE INDEX IF NOT EXISTS idx_emr_search_doctor ON emr_search_index(doctor_name);
|
||||
CREATE INDEX IF NOT EXISTS idx_emr_search_dept ON emr_search_index(department_name);
|
||||
|
||||
-- emr_revision 索引
|
||||
CREATE INDEX IF NOT EXISTS idx_emr_revision_emr ON emr_revision(emr_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_emr_revision_operator ON emr_revision(operator_name);
|
||||
@@ -18,7 +18,8 @@
|
||||
ihri.ward_name,
|
||||
ihri.contract_no,
|
||||
ihri.bus_no,
|
||||
ihri.admit_source_code
|
||||
ihri.admit_source_code,
|
||||
ihri.status_enum
|
||||
from (SELECT ae.tenant_id,
|
||||
ae.ID AS encounter_id,
|
||||
ae.amb_encounter_id AS amb_encounter_id,
|
||||
@@ -32,7 +33,8 @@
|
||||
al.NAME AS ward_name,
|
||||
aa.contract_no,
|
||||
ae.bus_no,
|
||||
ae.admit_source_code
|
||||
ae.admit_source_code,
|
||||
ae.status_enum
|
||||
FROM adm_encounter AS ae
|
||||
LEFT JOIN adm_encounter AS ambae ON ae.amb_encounter_id = ambae.
|
||||
ID
|
||||
|
||||
@@ -154,7 +154,11 @@
|
||||
ii.account_id AS account_id,
|
||||
ii.performer_check_id,
|
||||
ii.category_code,
|
||||
ii.dispense_status
|
||||
ii.dispense_status,
|
||||
ii.unit_price,
|
||||
ii.total_price,
|
||||
ii.stopper_id,
|
||||
ii.stopper_name
|
||||
FROM (( SELECT DISTINCT T1.encounter_id,
|
||||
T1.tenant_id,
|
||||
#{medMedicationRequest} AS advice_table,
|
||||
@@ -199,7 +203,11 @@
|
||||
personal_account.balance_amount,
|
||||
personal_account.id AS account_id,
|
||||
T2.category_code,
|
||||
mmd.status_enum AS dispense_status
|
||||
mmd.status_enum AS dispense_status,
|
||||
NULL::numeric AS unit_price,
|
||||
NULL::numeric AS total_price,
|
||||
NULL::bigint AS stopper_id,
|
||||
T1.update_by AS stopper_name
|
||||
FROM med_medication_request AS T1
|
||||
LEFT JOIN med_medication_definition AS T2
|
||||
ON T2.id = T1.medication_id
|
||||
@@ -341,7 +349,11 @@
|
||||
personal_account.balance_amount,
|
||||
personal_account.id AS account_id,
|
||||
T2.category_code,
|
||||
NULL::integer AS dispense_status
|
||||
NULL::integer AS dispense_status,
|
||||
NULL::numeric AS unit_price,
|
||||
NULL::numeric AS total_price,
|
||||
NULL::bigint AS stopper_id,
|
||||
T1.update_by AS stopper_name
|
||||
FROM wor_service_request AS T1
|
||||
LEFT JOIN wor_activity_definition AS T2
|
||||
ON T2.id = T1.activity_id
|
||||
|
||||
@@ -38,7 +38,18 @@
|
||||
pt.link_telcom,
|
||||
pt.link_jsons,
|
||||
pt.organization_id,
|
||||
pt.create_time
|
||||
pt.create_time,
|
||||
pt.postal_code,
|
||||
pt.hukou_address,
|
||||
pt.guardian_name,
|
||||
pt.guardian_relation,
|
||||
pt.guardian_phone,
|
||||
pt.guardian_id_type,
|
||||
pt.guardian_id_no,
|
||||
pt.guardian_address,
|
||||
pt.patient_derived,
|
||||
pt.education_level,
|
||||
pt.company_address
|
||||
FROM (
|
||||
SELECT
|
||||
(
|
||||
@@ -81,7 +92,18 @@
|
||||
p.link_telcom,
|
||||
p.link_jsons,
|
||||
p.organization_id,
|
||||
p.create_time
|
||||
p.create_time,
|
||||
p.postal_code,
|
||||
p.hukou_address,
|
||||
p.guardian_name,
|
||||
p.guardian_relation,
|
||||
p.guardian_phone,
|
||||
p.guardian_id_type,
|
||||
p.guardian_id_no,
|
||||
p.guardian_address,
|
||||
p.patient_derived,
|
||||
p.education_level,
|
||||
p.company_address
|
||||
FROM adm_patient p
|
||||
where p.delete_flag = '0'
|
||||
) AS pt
|
||||
|
||||
@@ -189,6 +189,7 @@
|
||||
T1.id AS request_id,
|
||||
T1.id || '-1' AS unique_key,
|
||||
T1.practitioner_id AS requester_id,
|
||||
ap.name AS requester_id_dict_text,
|
||||
T1.create_time AS request_time,
|
||||
CASE WHEN T1.practitioner_id = #{practitionerId} THEN '1' ELSE '0' END AS biz_request_flag,
|
||||
T1.content_json AS content_json,
|
||||
@@ -223,6 +224,7 @@
|
||||
T1.effective_dose_end AS stop_time,
|
||||
T1.update_by AS stop_user_name
|
||||
FROM med_medication_request AS T1
|
||||
LEFT JOIN adm_practitioner AS ap ON ap.id = T1.practitioner_id AND ap.delete_flag = '0'
|
||||
LEFT JOIN med_medication_definition AS T2 ON T2.ID = T1.medication_id
|
||||
AND T2.delete_flag = '0'
|
||||
LEFT JOIN med_medication AS T3 ON T3.medication_def_id = T2.ID
|
||||
@@ -246,6 +248,7 @@
|
||||
T1.id AS request_id,
|
||||
T1.id || '-2' AS unique_key,
|
||||
T1.requester_id AS requester_id,
|
||||
ap.name AS requester_id_dict_text,
|
||||
T1.create_time AS request_time,
|
||||
CASE WHEN T1.requester_id = #{practitionerId} THEN '1' ELSE '0' END AS biz_request_flag,
|
||||
T1.content_json AS content_json,
|
||||
@@ -280,6 +283,7 @@
|
||||
NULL::timestamp AS stop_time,
|
||||
'' AS stop_user_name
|
||||
FROM wor_device_request AS T1
|
||||
LEFT JOIN adm_practitioner AS ap ON ap.id = T1.requester_id AND ap.delete_flag = '0'
|
||||
LEFT JOIN adm_device_definition AS T2 ON T2.ID = T1.device_def_id
|
||||
AND T2.delete_flag = '0'
|
||||
LEFT JOIN adm_charge_item AS T3
|
||||
@@ -300,6 +304,7 @@
|
||||
T1.id AS request_id,
|
||||
T1.id || '-3' AS unique_key,
|
||||
T1.requester_id AS requester_id,
|
||||
ap.name AS requester_id_dict_text,
|
||||
T1.create_time AS request_time,
|
||||
CASE WHEN T1.requester_id = #{practitionerId} THEN '1' ELSE '0' END AS biz_request_flag,
|
||||
T1.content_json AS content_json,
|
||||
@@ -334,6 +339,7 @@
|
||||
T1.occurrence_end_time AS stop_time,
|
||||
T1.update_by AS stop_user_name
|
||||
FROM wor_service_request AS T1
|
||||
LEFT JOIN adm_practitioner AS ap ON ap.id = T1.requester_id AND ap.delete_flag = '0'
|
||||
LEFT JOIN wor_activity_definition AS T2
|
||||
ON T2.ID = T1.activity_id
|
||||
AND T2.delete_flag = '0'
|
||||
|
||||
@@ -22,7 +22,9 @@ public enum EncounterZyStatus implements HisEnumInterface {
|
||||
|
||||
PENDING_TRANSFER(6, "pending-transfer", "待转科"),
|
||||
|
||||
ALREADY_SETTLED(7, "already-settled", "已结算出院");
|
||||
ALREADY_SETTLED(7, "already-settled", "已结算出院"),
|
||||
|
||||
VOIDED(8, "voided", "已作废");
|
||||
|
||||
@EnumValue
|
||||
private final Integer value;
|
||||
|
||||
@@ -74,6 +74,11 @@ public enum RequestStatus implements HisEnumInterface {
|
||||
*/
|
||||
CHECK_RECEIVED(12, "check_received", "已接收"),
|
||||
|
||||
/**
|
||||
* 已停嘱(医生停嘱,等待护士核对)
|
||||
*/
|
||||
PENDING_STOP(13, "pending_stop", "已停嘱"),
|
||||
|
||||
/**
|
||||
* 已完成(药品发药完成)
|
||||
*/
|
||||
|
||||
@@ -130,4 +130,37 @@ public class Patient extends HisBaseEntity {
|
||||
/** 机构Id */
|
||||
private Long organizationId;
|
||||
|
||||
/** 邮政编码 */
|
||||
private String postalCode;
|
||||
|
||||
/** 户籍地址 */
|
||||
private String hukouAddress;
|
||||
|
||||
/** 监护人姓名 */
|
||||
private String guardianName;
|
||||
|
||||
/** 监护人关系 */
|
||||
private Integer guardianRelation;
|
||||
|
||||
/** 监护人电话 */
|
||||
private String guardianPhone;
|
||||
|
||||
/** 监护人证件类型 */
|
||||
private String guardianIdType;
|
||||
|
||||
/** 监护人证件号码 */
|
||||
private String guardianIdNo;
|
||||
|
||||
/** 监护人地址 */
|
||||
private String guardianAddress;
|
||||
|
||||
/** 患者来源 */
|
||||
private String patientDerived;
|
||||
|
||||
/** 文化程度 */
|
||||
private String educationLevel;
|
||||
|
||||
/** 单位地址 */
|
||||
private String companyAddress;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
/* eslint-env node */
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import globals from "globals";
|
||||
import pluginVue from "eslint-plugin-vue";
|
||||
import parserVue from "vue-eslint-parser";
|
||||
import importPlugin from "eslint-plugin-import";
|
||||
import importPlugin, { createNodeResolver } from "eslint-plugin-import-x";
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
export default [
|
||||
{
|
||||
@@ -29,31 +33,31 @@ export default [
|
||||
},
|
||||
|
||||
plugins: {
|
||||
import: importPlugin,
|
||||
"import-x": importPlugin,
|
||||
},
|
||||
|
||||
rules: {
|
||||
// 确保导入的模块实际存在(核心规则,防止构建失败)
|
||||
"import/no-unresolved": "error",
|
||||
"import-x/no-unresolved": "error",
|
||||
// 确保导入的命名导出实际存在
|
||||
"import/named": "error",
|
||||
"import-x/named": "error",
|
||||
// 确保默认导出存在
|
||||
"import/default": "error",
|
||||
"import-x/default": "error",
|
||||
// 确保命名空间导出存在
|
||||
"import/namespace": "error",
|
||||
"import-x/namespace": "error",
|
||||
// Vue 相关规则
|
||||
"vue/multi-word-component-names": "off",
|
||||
},
|
||||
|
||||
settings: {
|
||||
"import/resolver": {
|
||||
alias: {
|
||||
map: [
|
||||
["@", "./src"],
|
||||
],
|
||||
extensions: [".js", ".jsx", ".vue"],
|
||||
},
|
||||
},
|
||||
"import-x/resolver-next": [
|
||||
createNodeResolver({
|
||||
alias: {
|
||||
"@": [path.join(__dirname, "src")],
|
||||
},
|
||||
extensions: [".mjs", ".cjs", ".js", ".jsx", ".vue", ".json", ".node"],
|
||||
}),
|
||||
],
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@@ -75,8 +75,7 @@
|
||||
"@vitejs/plugin-vue": "^5.2.4",
|
||||
"@vue/test-utils": "^2.4.6",
|
||||
"eslint": "^10.4.1",
|
||||
"eslint-import-resolver-alias": "^1.1.2",
|
||||
"eslint-plugin-import": "^2.32.0",
|
||||
"eslint-plugin-import-x": "^4.16.1",
|
||||
"eslint-plugin-vue": "^10.9.1",
|
||||
"globals": "^17.5.0",
|
||||
"happy-dom": "^20.8.3",
|
||||
|
||||
@@ -2,51 +2,51 @@ import request from '@/utils/request'
|
||||
|
||||
// ==================== 处方审核 ====================
|
||||
export function auditPrescription(data) {
|
||||
return request({ url: '/healthlink-his/api/v1/rational-drug/audit', method: 'post', data })
|
||||
return request({ url: '/api/v1/rational-drug/audit', method: 'post', data })
|
||||
}
|
||||
|
||||
export function batchAudit(prescriptionIds) {
|
||||
return request({ url: '/healthlink-his/api/v1/rational-drug/batch-audit', method: 'post', data: prescriptionIds })
|
||||
return request({ url: '/api/v1/rational-drug/batch-audit', method: 'post', data: prescriptionIds })
|
||||
}
|
||||
|
||||
export function getAuditStatistics() {
|
||||
return request({ url: '/healthlink-his/api/v1/rational-drug/statistics', method: 'get' })
|
||||
return request({ url: '/api/v1/rational-drug/statistics', method: 'get' })
|
||||
}
|
||||
|
||||
export function getAuditTrend(startDate) {
|
||||
return request({ url: '/healthlink-his/api/v1/rational-drug/trend', method: 'get', params: { startDate } })
|
||||
return request({ url: '/api/v1/rational-drug/trend', method: 'get', params: { startDate } })
|
||||
}
|
||||
|
||||
export function getAuditLog(encounterId) {
|
||||
return request({ url: `/healthlink-his/api/v1/rational-drug/audit-log/${encounterId}`, method: 'get' })
|
||||
return request({ url: `/api/v1/rational-drug/audit-log/${encounterId}`, method: 'get' })
|
||||
}
|
||||
|
||||
// ==================== 配伍禁忌 ====================
|
||||
export function checkInteraction(drugCodes) {
|
||||
return request({ url: '/healthlink-his/api/v1/rational-drug/check-interaction', method: 'post', data: drugCodes })
|
||||
return request({ url: '/api/v1/rational-drug/check-interaction', method: 'post', data: drugCodes })
|
||||
}
|
||||
|
||||
export function listInteractionRules(params) {
|
||||
return request({ url: '/healthlink-his/api/v1/rational-drug/interaction-rules', method: 'get', params })
|
||||
return request({ url: '/api/v1/rational-drug/interaction-rules', method: 'get', params })
|
||||
}
|
||||
|
||||
export function addInteractionRule(data) {
|
||||
return request({ url: '/healthlink-his/api/v1/rational-drug/interaction-rules', method: 'post', data })
|
||||
return request({ url: '/api/v1/rational-drug/interaction-rules', method: 'post', data })
|
||||
}
|
||||
|
||||
export function updateInteractionRule(data) {
|
||||
return request({ url: '/healthlink-his/api/v1/rational-drug/interaction-rules', method: 'put', data })
|
||||
return request({ url: '/api/v1/rational-drug/interaction-rules', method: 'put', data })
|
||||
}
|
||||
|
||||
export function delInteractionRule(id) {
|
||||
return request({ url: `/healthlink-his/api/v1/rational-drug/interaction-rules/${id}`, method: 'delete' })
|
||||
return request({ url: `/api/v1/rational-drug/interaction-rules/${id}`, method: 'delete' })
|
||||
}
|
||||
|
||||
// ==================== 剂量规则 ====================
|
||||
export function listDosageRules(params) {
|
||||
return request({ url: '/healthlink-his/api/v1/rational-drug/dosage-rules', method: 'get', params })
|
||||
return request({ url: '/api/v1/rational-drug/dosage-rules', method: 'get', params })
|
||||
}
|
||||
|
||||
export function checkDosage(drugCode, dosage, population) {
|
||||
return request({ url: '/healthlink-his/api/v1/rational-drug/check-dosage', method: 'get', params: { drugCode, dosage, population } })
|
||||
return request({ url: '/api/v1/rational-drug/check-dosage', method: 'get', params: { drugCode, dosage, population } })
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import request from '@/utils/request'
|
||||
// 处方审核
|
||||
export function auditPrescription(data) {
|
||||
return request({
|
||||
url: '/healthlink-his/api/v1/rational-drug/audit',
|
||||
url: '/api/v1/rational-drug/audit',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
@@ -12,7 +12,7 @@ export function auditPrescription(data) {
|
||||
// 批量审核
|
||||
export function batchAudit(data) {
|
||||
return request({
|
||||
url: '/healthlink-his/api/v1/rational-drug/batch-audit',
|
||||
url: '/api/v1/rational-drug/batch-audit',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
@@ -21,7 +21,7 @@ export function batchAudit(data) {
|
||||
// 审核统计
|
||||
export function getAuditStatistics() {
|
||||
return request({
|
||||
url: '/healthlink-his/api/v1/rational-drug/statistics',
|
||||
url: '/api/v1/rational-drug/statistics',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
@@ -29,7 +29,7 @@ export function getAuditStatistics() {
|
||||
// 审核趋势
|
||||
export function getAuditTrend(params) {
|
||||
return request({
|
||||
url: '/healthlink-his/api/v1/rational-drug/trend',
|
||||
url: '/api/v1/rational-drug/trend',
|
||||
method: 'get',
|
||||
params: params
|
||||
})
|
||||
@@ -38,7 +38,7 @@ export function getAuditTrend(params) {
|
||||
// 审核记录
|
||||
export function getAuditLog(encounterId) {
|
||||
return request({
|
||||
url: '/healthlink-his/api/v1/rational-drug/audit-log/' + encounterId,
|
||||
url: '/api/v1/rational-drug/audit-log/' + encounterId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
@@ -46,7 +46,7 @@ export function getAuditLog(encounterId) {
|
||||
// 配伍禁忌检查
|
||||
export function checkInteraction(data) {
|
||||
return request({
|
||||
url: '/healthlink-his/api/v1/rational-drug/check-interaction',
|
||||
url: '/api/v1/rational-drug/check-interaction',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
@@ -55,7 +55,7 @@ export function checkInteraction(data) {
|
||||
// 配伍禁忌规则列表
|
||||
export function listInteractionRules(params) {
|
||||
return request({
|
||||
url: '/healthlink-his/api/v1/rational-drug/interaction-rules',
|
||||
url: '/api/v1/rational-drug/interaction-rules',
|
||||
method: 'get',
|
||||
params: params
|
||||
})
|
||||
@@ -64,7 +64,7 @@ export function listInteractionRules(params) {
|
||||
// 新增配伍禁忌规则
|
||||
export function addInteractionRule(data) {
|
||||
return request({
|
||||
url: '/healthlink-his/api/v1/rational-drug/interaction-rules',
|
||||
url: '/api/v1/rational-drug/interaction-rules',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
@@ -73,7 +73,7 @@ export function addInteractionRule(data) {
|
||||
// 修改配伍禁忌规则
|
||||
export function updateInteractionRule(data) {
|
||||
return request({
|
||||
url: '/healthlink-his/api/v1/rational-drug/interaction-rules',
|
||||
url: '/api/v1/rational-drug/interaction-rules',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
@@ -82,7 +82,7 @@ export function updateInteractionRule(data) {
|
||||
// 删除配伍禁忌规则
|
||||
export function delInteractionRule(id) {
|
||||
return request({
|
||||
url: '/healthlink-his/api/v1/rational-drug/interaction-rules/' + id,
|
||||
url: '/api/v1/rational-drug/interaction-rules/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
@@ -90,7 +90,7 @@ export function delInteractionRule(id) {
|
||||
// 剂量规则列表
|
||||
export function listDosageRules(params) {
|
||||
return request({
|
||||
url: '/healthlink-his/api/v1/rational-drug/dosage-rules',
|
||||
url: '/api/v1/rational-drug/dosage-rules',
|
||||
method: 'get',
|
||||
params: params
|
||||
})
|
||||
|
||||
@@ -71,6 +71,14 @@ router.beforeEach(async (to, from) => {
|
||||
return { path: '/login' }
|
||||
}
|
||||
}
|
||||
// 铁律: 路由权限校验 — 目标路由必须在已注册的路由中存在
|
||||
// 防止切换账户后,通过旧标签或直接输入 URL 访问无权限页面
|
||||
const resolved = router.resolve(to)
|
||||
if (resolved.matched.length === 0 || resolved.name === 'NotFound') {
|
||||
// 路由不存在(未注册),拒绝导航
|
||||
ElMessage.warning('无权访问该页面')
|
||||
return { path: '/' }
|
||||
}
|
||||
return true
|
||||
} else {
|
||||
if (isWhiteList(to.path)) {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {getInfo, login, logout} from '@/api/login'
|
||||
import useTagsViewStore from '@/store/modules/tagsView'
|
||||
import {getToken, removeToken, setToken} from '@/utils/auth'
|
||||
import defAva from '@/assets/images/user.png'
|
||||
import {defineStore} from 'pinia'
|
||||
@@ -84,6 +85,8 @@ const useUserStore = defineStore(
|
||||
this.permissions = []
|
||||
this.tenantId = ''
|
||||
removeToken()
|
||||
// 清除标签页内存状态,防止切换账户时残留
|
||||
try { useTagsViewStore().delAllViews() } catch(e) {}
|
||||
resolve()
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
|
||||
@@ -40,6 +40,8 @@ export const RequestStatus = {
|
||||
PENDING_RECEIVE: 11,
|
||||
/** 已接收(检查申请:医技科室已接单) */
|
||||
CHECK_RECEIVED: 12,
|
||||
/** 已停嘱(医生停嘱,等待护士核对) */
|
||||
PENDING_STOP: 13,
|
||||
/** 已完成(药品发药完成) */
|
||||
DISPENSE_COMPLETED: 20,
|
||||
};
|
||||
@@ -59,6 +61,7 @@ export const RequestStatusDescriptions = {
|
||||
10: '已校对',
|
||||
11: '待接收',
|
||||
12: '已接收',
|
||||
13: '已停嘱',
|
||||
20: '已完成',
|
||||
};
|
||||
|
||||
|
||||
@@ -92,6 +92,7 @@
|
||||
placeholder="请选"
|
||||
class="inline-select"
|
||||
:disabled="!isEditMode"
|
||||
clearable
|
||||
>
|
||||
<el-option
|
||||
v-for="doctor in getDoctorOptions(filterParams.appointmentType)"
|
||||
@@ -113,6 +114,7 @@
|
||||
placeholder="请选"
|
||||
class="inline-select"
|
||||
:disabled="!isEditMode"
|
||||
clearable
|
||||
>
|
||||
<el-option
|
||||
label="诊室1"
|
||||
@@ -206,6 +208,7 @@
|
||||
placeholder="请选"
|
||||
class="inline-select"
|
||||
:disabled="!isEditMode"
|
||||
clearable
|
||||
@change="handleAppointmentItemChange(scope.row)"
|
||||
>
|
||||
<el-option
|
||||
@@ -247,6 +250,7 @@
|
||||
placeholder="请选择诊查项目"
|
||||
class="inline-select"
|
||||
:disabled="!isEditMode"
|
||||
clearable
|
||||
@change="handleClinicItemChange(scope.row)"
|
||||
>
|
||||
<el-option
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<div class="appoinmentmanage-wrapper">
|
||||
<div class="appoinmentmanage-container">
|
||||
<div class="appoinmentmanage-header">
|
||||
@@ -335,6 +335,7 @@
|
||||
v-model="scope.row.doctorId"
|
||||
placeholder="请选"
|
||||
class="inline-select"
|
||||
clearable
|
||||
:disabled="!isEditMode"
|
||||
@change="(selectedId) => handleDoctorChange(selectedId, scope.row)"
|
||||
>
|
||||
@@ -359,6 +360,7 @@
|
||||
filterable
|
||||
:remote-method="searchClinicRooms"
|
||||
class="inline-select"
|
||||
clearable
|
||||
:disabled="!isEditMode"
|
||||
>
|
||||
<el-option
|
||||
@@ -443,6 +445,7 @@
|
||||
v-model="scope.row.appointmentItem"
|
||||
placeholder="请选"
|
||||
class="inline-select"
|
||||
clearable
|
||||
:disabled="!isEditMode"
|
||||
@change="handleAppointmentItemChange(scope.row)"
|
||||
>
|
||||
@@ -474,6 +477,7 @@
|
||||
v-model="scope.row.clinicItem"
|
||||
placeholder="请选择诊查项目"
|
||||
class="inline-select"
|
||||
clearable
|
||||
:disabled="!isEditMode"
|
||||
@change="handleClinicItemChange(scope.row)"
|
||||
>
|
||||
|
||||
@@ -447,15 +447,65 @@
|
||||
v-model="form.deceasedDate"
|
||||
type="datetime"
|
||||
placeholder="请选择时间"
|
||||
format="YYYY/MM/DD HH:mm:ss"
|
||||
format="YYYY-MM-DD HH:mm:ss"
|
||||
:disabled="isViewMode"
|
||||
value-format="YYYY/MM/DD HH:mm:ss"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 第八行:监护人、监护人关系、监护人电话 -->
|
||||
|
||||
<!-- 第八行:联系人、联系人关系、联系人电话 -->
|
||||
<el-row>
|
||||
<el-col :span="8">
|
||||
<el-form-item
|
||||
label="联系人"
|
||||
prop="linkName"
|
||||
>
|
||||
<el-input
|
||||
v-model="form.linkName"
|
||||
clearable
|
||||
:disabled="isViewMode"
|
||||
placeholder="请输入联系人"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item
|
||||
label="联系人关系"
|
||||
prop="linkRelationCode"
|
||||
>
|
||||
<el-select
|
||||
v-model="form.linkRelationCode"
|
||||
placeholder="联系人关系"
|
||||
clearable
|
||||
:disabled="isViewMode"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in link_relation_code"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item
|
||||
label="联系人电话"
|
||||
prop="linkTelcom"
|
||||
>
|
||||
<el-input
|
||||
v-model="form.linkTelcom"
|
||||
clearable
|
||||
:disabled="isViewMode"
|
||||
placeholder="请输入联系人电话"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 第九行:监护人、监护人关系、监护人电话 -->
|
||||
<el-row>
|
||||
<el-col :span="8">
|
||||
<el-form-item
|
||||
@@ -702,12 +752,26 @@ const getGenderOptions = async () => {
|
||||
const getEducationLevelOptions = async () => {
|
||||
try {
|
||||
// 从字典管理获取文化程度数据
|
||||
const response = await getDicts('文化程度');
|
||||
const response = await getDicts('educational_level');
|
||||
console.log('获取到的文化程度原始数据:', response);
|
||||
|
||||
// 确保数据是数组
|
||||
if (!response || response.code !== 200 || !Array.isArray(response.data)) {
|
||||
console.error('文化程度数据格式错误:', response);
|
||||
// 确保数据是数组且非空
|
||||
if (!response || response.code !== 200 || !Array.isArray(response.data) || response.data.length === 0) {
|
||||
console.warn('文化程度数据为空或格式错误,使用默认数据:', response);
|
||||
// 降级方案:使用默认的文化程度选项,按编码顺序排列
|
||||
educationLevelList.value = [
|
||||
{ value: '1', info: '大学本科' },
|
||||
{ value: '2', info: '硕士研究生' },
|
||||
{ value: '3', info: '博士研究生' },
|
||||
{ value: '4', info: '初中毕业' },
|
||||
{ value: '5', info: '大学专科结业' },
|
||||
{ value: '6', info: '技工学院结业' },
|
||||
{ value: '7', info: '职业高中结业' },
|
||||
{ value: '8', info: '小学毕业' },
|
||||
{ value: '9', info: '普通高中结业' },
|
||||
{ value: '10', info: '中等专科结业' },
|
||||
{ value: '99', info: '其他' }
|
||||
];
|
||||
return;
|
||||
}
|
||||
const educationDict = response.data;
|
||||
@@ -743,17 +807,18 @@ const getEducationLevelOptions = async () => {
|
||||
console.error('获取文化程度字典数据失败:', error);
|
||||
// 降级方案:使用默认的文化程度选项,按编码顺序排列
|
||||
educationLevelList.value = [
|
||||
{ value: '3912', info: '大学本科' },
|
||||
{ value: '3913', info: '硕士研究生' },
|
||||
{ value: '3914', info: '博士研究生' },
|
||||
{ value: '3915', info: '初中毕业' },
|
||||
{ value: '3916', info: '大学毕业' },
|
||||
{ value: '3917', info: '技工学校毕业' },
|
||||
{ value: '3918', info: '职业高中毕业' },
|
||||
{ value: '3919', info: '小学毕业' },
|
||||
{ value: '3920', info: '普通高中毕业' },
|
||||
{ value: '3921', info: '中等专科毕业' }
|
||||
].sort((a, b) => parseInt(a.value) - parseInt(b.value)); // 确保默认选项也按编码排序
|
||||
{ value: '1', info: '大学本科' },
|
||||
{ value: '2', info: '硕士研究生' },
|
||||
{ value: '3', info: '博士研究生' },
|
||||
{ value: '4', info: '初中毕业' },
|
||||
{ value: '5', info: '大学专科结业' },
|
||||
{ value: '6', info: '技工学院结业' },
|
||||
{ value: '7', info: '职业高中结业' },
|
||||
{ value: '8', info: '小学毕业' },
|
||||
{ value: '9', info: '普通高中结业' },
|
||||
{ value: '10', info: '中等专科结业' },
|
||||
{ value: '99', info: '其他' }
|
||||
];
|
||||
}
|
||||
};
|
||||
const options = ref(pcas); // 地区数据
|
||||
@@ -1403,10 +1468,8 @@ const getCountryCodeOptions = async () => {
|
||||
|
||||
// 显示弹框
|
||||
function show() {
|
||||
// 重置为新增模式
|
||||
isEditMode.value = false;
|
||||
title.value = '新增患者';
|
||||
originalFormData.value = {};
|
||||
// 重置表单为初始状态
|
||||
reset();
|
||||
|
||||
// queryParams.roleId = props.roleId;
|
||||
getList();
|
||||
@@ -1452,6 +1515,22 @@ function reset() {
|
||||
busNo: undefined,
|
||||
organizationId: undefined,
|
||||
birthDate: undefined,
|
||||
postalCode: undefined,
|
||||
hukouAddress: undefined,
|
||||
hukouAddressSelect: undefined,
|
||||
hukouAddressProvince: undefined,
|
||||
hukouAddressCity: undefined,
|
||||
hukouAddressDistrict: undefined,
|
||||
hukouAddressStreet: undefined,
|
||||
companyAddress: undefined,
|
||||
patientDerived: undefined,
|
||||
educationLevel: undefined,
|
||||
guardianName: undefined,
|
||||
guardianRelation: undefined,
|
||||
guardianPhone: undefined,
|
||||
guardianIdType: undefined,
|
||||
guardianIdNo: undefined,
|
||||
guardianAddress: undefined,
|
||||
};
|
||||
// 重置编辑模式状态
|
||||
isEditMode.value = false;
|
||||
@@ -1509,6 +1588,18 @@ function submitForm() {
|
||||
if (!form.value.identifierNo) {
|
||||
form.value.typeCode = undefined;
|
||||
}
|
||||
// 修复死亡时间日期格式:确保 yyyy-MM-dd HH:mm:ss 格式
|
||||
if (form.value.deceasedDate) {
|
||||
const d = form.value.deceasedDate;
|
||||
if (d instanceof Date) {
|
||||
const pad = (n) => String(n).padStart(2, '0');
|
||||
form.value.deceasedDate = d.getFullYear() + '-' + pad(d.getMonth() + 1) + '-' + pad(d.getDate()) + ' ' + pad(d.getHours()) + ':' + pad(d.getMinutes()) + ':' + pad(d.getSeconds());
|
||||
} else if (typeof d === 'string') {
|
||||
// 将任何非标准格式转为 yyyy-MM-dd HH:mm:ss
|
||||
const normalized = d.replace(/\//g, '-').replace(/T/, ' ').replace(/\.\d+Z?$/, '').trim();
|
||||
form.value.deceasedDate = normalized;
|
||||
}
|
||||
}
|
||||
// 拼接完整地址用于提交,但不覆写表单字段(避免弹窗关闭前显示全地址)
|
||||
const submitData = { ...form.value, address: getAddress(form) };
|
||||
|
||||
|
||||
@@ -263,9 +263,8 @@ const handleCurrentChange = (currentRow) => {
|
||||
currentSelectRow.value = currentRow;
|
||||
};
|
||||
|
||||
function clickRow(row, column, cell, event) {
|
||||
// cell-click 事件会传递 row, column, cell, event 四个参数
|
||||
// 确保传递的是完整的行数据
|
||||
function clickRow({ row }) {
|
||||
// vxe-table 4.x cell-click 事件参数是 { row, column, ... } 对象,需解构取 row
|
||||
if (row) {
|
||||
emit('selectAdviceBase', row);
|
||||
}
|
||||
|
||||
@@ -38,170 +38,15 @@
|
||||
max-height="650"
|
||||
:data="prescriptionList"
|
||||
:row-config="{ keyField: 'uniqueKey', expandRowKeys: expandOrder }"
|
||||
:column-config="{ resizable: true }"
|
||||
border
|
||||
auto-resize
|
||||
@cell-dblclick="clickRowDb"
|
||||
>
|
||||
<vxe-column
|
||||
type="expand"
|
||||
width="40"
|
||||
>
|
||||
<template #default="scope">
|
||||
<el-form
|
||||
:ref="'formRef' + scope.rowIndex"
|
||||
:model="scope.row"
|
||||
:rules="rowRules"
|
||||
>
|
||||
<div style="padding: 16px; background: #f8f9fa; border-radius: 8px">
|
||||
<!-- 药品类型(adviceType == 1)和耗材类型(adviceType == 2)使用相同的界面 -->
|
||||
<template v-if="scope.row.adviceType == 1 || scope.row.adviceType == 2">
|
||||
<div style="display: flex; align-items: center; margin-bottom: 16px; gap: 16px">
|
||||
<span style="font-size: 16px; font-weight: 600">
|
||||
{{
|
||||
scope.row.adviceName +
|
||||
' ' +
|
||||
(scope.row.volume ? scope.row.volume + ' ' : '') +
|
||||
(scope.row.unitPrice ? scope.row.unitPrice + ' 元/' : '') +
|
||||
(scope.row.unitCode_dictText || '')
|
||||
}}
|
||||
</span>
|
||||
<div class="form-group">
|
||||
<!-- 库存不为空时显示批号选择 -->
|
||||
<el-select
|
||||
v-if="scope.row.stockList && scope.row.stockList.length > 0"
|
||||
v-model="scope.row.lotNumber"
|
||||
style="width: 180px; margin-right: 20px"
|
||||
placeholder="选择批号"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in scope.row.stockList"
|
||||
:key="item.lotNumber"
|
||||
:value="item.lotNumber"
|
||||
:label="
|
||||
item.locationName +
|
||||
' ' +
|
||||
'批次号: ' +
|
||||
item.lotNumber +
|
||||
' ' +
|
||||
' 库存:' +
|
||||
(item.quantity / scope.row.partPercent).toFixed(2) +
|
||||
item.unitCode_dictText +
|
||||
' 单价:' +
|
||||
item.price.toFixed(2) +
|
||||
'/' +
|
||||
item.unitCode_dictText
|
||||
"
|
||||
@click="handleNumberClick(item, scope.rowIndex)"
|
||||
/>
|
||||
</el-select>
|
||||
<!-- 库存为空时显示提示 -->
|
||||
<span
|
||||
v-else
|
||||
style="color: #EF4444; margin-right: 20px; font-size: 14px;"
|
||||
>
|
||||
无可用库存
|
||||
</span>
|
||||
<el-form-item
|
||||
label="数量:"
|
||||
prop="quantity"
|
||||
class="required-field"
|
||||
data-prop="quantity"
|
||||
>
|
||||
<el-input-number
|
||||
v-model="scope.row.quantity"
|
||||
placeholder="数量"
|
||||
style="width: 70px"
|
||||
controls-position="right"
|
||||
:controls="false"
|
||||
@keyup.enter.prevent="handleEnter('quantity', scope.row, scope.rowIndex)"
|
||||
@input="calculateTotalPrice(scope.row, scope.rowIndex)"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-select
|
||||
v-if="scope.row.unitCodeList && scope.row.unitCodeList.length > 0"
|
||||
v-model="scope.row.unitCode"
|
||||
style="width: 70px; margin-right: 20px"
|
||||
placeholder="单位"
|
||||
@change="calculateTotalAmount(scope.row, scope.rowIndex)"
|
||||
>
|
||||
<template
|
||||
v-for="item in scope.row.unitCodeList"
|
||||
:key="item.value"
|
||||
>
|
||||
<el-option
|
||||
v-if="item.type != unitMap['dose']"
|
||||
:value="item.value"
|
||||
:label="item.label"
|
||||
/>
|
||||
</template>
|
||||
</el-select>
|
||||
<span class="total-amount">
|
||||
总金额:{{ scope.row.totalPrice ? scope.row.totalPrice + ' 元' : '0.00 元' }}
|
||||
</span>
|
||||
</div>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="handleSaveSign(scope.row, scope.rowIndex)"
|
||||
>
|
||||
保存
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div style="display: flex; align-items: center; margin-bottom: 16px; gap: 16px">
|
||||
<span style="font-size: 16px; font-weight: 600">
|
||||
{{
|
||||
scope.row.adviceName + ' ' + scope.row.unitPrice
|
||||
? Number(scope.row.unitPrice).toFixed(2)
|
||||
: '-' + '元'
|
||||
}}
|
||||
</span>
|
||||
<div class="form-group">
|
||||
<el-form-item
|
||||
label="执行次数:"
|
||||
prop="quantity"
|
||||
class="required-field"
|
||||
data-prop="quantity"
|
||||
>
|
||||
<el-input-number
|
||||
v-model="scope.row.quantity"
|
||||
placeholder="执行次数"
|
||||
style="width: 100px; margin: 0 20px"
|
||||
controls-position="right"
|
||||
:controls="false"
|
||||
@keyup.enter.prevent="handleEnter('quantity', scope.row, scope.rowIndex)"
|
||||
@input="calculateTotalPrice(scope.row, scope.rowIndex)"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-tree-select
|
||||
v-model="scope.row.orgId"
|
||||
clearable
|
||||
:data="organization"
|
||||
:props="{ value: 'id', label: 'name', children: 'children' }"
|
||||
value-key="id"
|
||||
check-strictly
|
||||
placeholder="请选择执行科室"
|
||||
style="min-width: 150px; width: auto;"
|
||||
class="org-select"
|
||||
/>
|
||||
<span class="total-amount">
|
||||
总金额:{{ scope.row.totalPrice ? scope.row.totalPrice + ' 元' : '0.00 元' }}
|
||||
</span>
|
||||
<span style="font-size: 16px; font-weight: 600">
|
||||
<!-- 金额: {{ scope.row.priceList[0].price }} -->
|
||||
</span>
|
||||
</div>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="handleSaveSign(scope.row, scope.rowIndex)"
|
||||
>
|
||||
保存
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</el-form>
|
||||
</template>
|
||||
</vxe-column>
|
||||
/>
|
||||
<vxe-column
|
||||
title=""
|
||||
align="center"
|
||||
@@ -370,6 +215,7 @@
|
||||
<vxe-column
|
||||
title="总量"
|
||||
align="center"
|
||||
width="100"
|
||||
field=""
|
||||
>
|
||||
<template #default="scope">
|
||||
@@ -383,6 +229,7 @@
|
||||
align="right"
|
||||
field=""
|
||||
header-align="center"
|
||||
width="130"
|
||||
>
|
||||
<template #default="scope">
|
||||
<span
|
||||
@@ -430,6 +277,151 @@
|
||||
</template>
|
||||
</vxe-column>
|
||||
</vxe-table>
|
||||
<!-- 编辑表单卡片:独立于表格,选中项目后显示在表格下方 -->
|
||||
<div
|
||||
v-if="editingRow"
|
||||
class="edit-form-card"
|
||||
>
|
||||
<el-form
|
||||
:ref="'editFormRef'"
|
||||
:model="editingRow"
|
||||
:rules="rowRules"
|
||||
>
|
||||
<div style="padding: 16px; background: #f8f9fa; border-radius: 8px">
|
||||
<template v-if="editingRow.adviceType == 1 || editingRow.adviceType == 2">
|
||||
<div style="display: flex; align-items: center; gap: 16px; flex-wrap: wrap">
|
||||
<span style="font-size: 16px; font-weight: 600">
|
||||
{{
|
||||
editingRow.adviceName +
|
||||
' ' +
|
||||
(editingRow.volume ? editingRow.volume + ' ' : '') +
|
||||
(editingRow.unitPrice ? editingRow.unitPrice + ' 元/' : '') +
|
||||
(editingRow.unitCode_dictText || '')
|
||||
}}
|
||||
</span>
|
||||
<div class="form-group">
|
||||
<el-select
|
||||
v-if="editingRow.stockList && editingRow.stockList.length > 0"
|
||||
v-model="editingRow.lotNumber"
|
||||
style="width: 180px; margin-right: 20px"
|
||||
placeholder="选择批号"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in editingRow.stockList"
|
||||
:key="item.lotNumber"
|
||||
:value="item.lotNumber"
|
||||
:label="
|
||||
item.locationName +
|
||||
' 批次号: ' + item.lotNumber +
|
||||
' 库存:' + (item.quantity / editingRow.partPercent).toFixed(2) +
|
||||
item.unitCode_dictText +
|
||||
' 单价:' + item.price.toFixed(2) + '/' + item.unitCode_dictText
|
||||
"
|
||||
@click="handleNumberClick(item, editingRowIndex)"
|
||||
/>
|
||||
</el-select>
|
||||
<span
|
||||
v-else
|
||||
style="color: #EF4444; margin-right: 20px; font-size: 14px;"
|
||||
>无可用库存</span>
|
||||
<el-form-item
|
||||
label="数量:"
|
||||
prop="quantity"
|
||||
class="required-field"
|
||||
data-prop="quantity"
|
||||
>
|
||||
<el-input-number
|
||||
v-model="editingRow.quantity"
|
||||
placeholder="数量"
|
||||
style="width: 70px"
|
||||
controls-position="right"
|
||||
:controls="false"
|
||||
@keyup.enter.prevent="handleEnter('quantity', editingRow, editingRowIndex)"
|
||||
@input="calculateTotalPrice(editingRow, editingRowIndex)"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-select
|
||||
v-if="editingRow.unitCodeList && editingRow.unitCodeList.length > 0"
|
||||
v-model="editingRow.unitCode"
|
||||
style="width: 70px; margin-right: 20px"
|
||||
placeholder="单位"
|
||||
@change="calculateTotalAmount(editingRow, editingRowIndex)"
|
||||
>
|
||||
<template
|
||||
v-for="item in editingRow.unitCodeList"
|
||||
:key="item.value"
|
||||
>
|
||||
<el-option
|
||||
v-if="item.type != unitMap['dose']"
|
||||
:value="item.value"
|
||||
:label="item.label"
|
||||
/>
|
||||
</template>
|
||||
</el-select>
|
||||
<span class="total-amount">
|
||||
总金额:{{ editingRow.totalPrice ? editingRow.totalPrice + ' 元' : '0.00 元' }}
|
||||
</span>
|
||||
</div>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="handleSaveSign(editingRow, editingRowIndex)"
|
||||
>
|
||||
保存
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div style="display: flex; align-items: center; gap: 16px; flex-wrap: wrap">
|
||||
<span style="font-size: 16px; font-weight: 600">
|
||||
{{
|
||||
editingRow.adviceName + ' ' + editingRow.unitPrice
|
||||
? Number(editingRow.unitPrice).toFixed(2)
|
||||
: '-' + '元'
|
||||
}}
|
||||
</span>
|
||||
<div class="form-group">
|
||||
<el-form-item
|
||||
label="执行次数:"
|
||||
prop="quantity"
|
||||
class="required-field"
|
||||
data-prop="quantity"
|
||||
>
|
||||
<el-input-number
|
||||
v-model="editingRow.quantity"
|
||||
placeholder="执行次数"
|
||||
style="width: 100px; margin: 0 20px"
|
||||
controls-position="right"
|
||||
:controls="false"
|
||||
@keyup.enter.prevent="handleEnter('quantity', editingRow, editingRowIndex)"
|
||||
@input="calculateTotalPrice(editingRow, editingRowIndex)"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-tree-select
|
||||
v-model="editingRow.orgId"
|
||||
clearable
|
||||
:data="organization"
|
||||
:props="{ value: 'id', label: 'name', children: 'children' }"
|
||||
value-key="id"
|
||||
check-strictly
|
||||
placeholder="请选择执行科室"
|
||||
style="min-width: 150px; width: auto;"
|
||||
class="org-select"
|
||||
/>
|
||||
<span class="total-amount">
|
||||
总金额:{{ editingRow.totalPrice ? editingRow.totalPrice + ' 元' : '0.00 元' }}
|
||||
</span>
|
||||
</div>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="handleSaveSign(editingRow, editingRowIndex)"
|
||||
>
|
||||
保存
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -444,7 +436,7 @@ import {
|
||||
getEncounterDiagnosis,
|
||||
} from './api';
|
||||
import adviceBaseList from './adviceBaseList';
|
||||
import {getCurrentInstance, nextTick, ref, watch} from 'vue';
|
||||
import {getCurrentInstance, nextTick, ref, watch, computed} from 'vue';
|
||||
|
||||
const emit = defineEmits(['selectDiagnosis']);
|
||||
const prescriptionList = ref([]);
|
||||
@@ -493,6 +485,14 @@ const isAdding = ref(false);
|
||||
const isSaving = ref(false); // #437 防重复提交锁
|
||||
const prescriptionRef = ref();
|
||||
const expandOrder = ref([]); //目前的展开行
|
||||
const editingRow = computed(() => {
|
||||
if (expandOrder.value.length === 0) return null;
|
||||
return prescriptionList.value.find(r => r.uniqueKey === expandOrder.value[0]) || null;
|
||||
});
|
||||
const editingRowIndex = computed(() => {
|
||||
if (expandOrder.value.length === 0) return -1;
|
||||
return prescriptionList.value.findIndex(r => r.uniqueKey === expandOrder.value[0]);
|
||||
});
|
||||
const stockList = ref([]);
|
||||
const groupList = ref([])
|
||||
const { proxy } = getCurrentInstance();
|
||||
@@ -546,8 +546,11 @@ watch(
|
||||
nextTick(() => {
|
||||
|
||||
const index = prescriptionList.value.findIndex((row) => row.uniqueKey === newValue[0]);
|
||||
const items = proxy.$refs['formRef' + index]?.$el?.querySelectorAll('[data-prop]');
|
||||
requiredProps.value = Array.from(items).map((item) => item.dataset.prop);
|
||||
const formEl = proxy.$refs['editFormRef'];
|
||||
if (formEl) {
|
||||
const items = formEl.$el?.querySelectorAll('[data-prop]') || formEl.querySelectorAll?.('[data-prop]');
|
||||
if (items) requiredProps.value = Array.from(items).map((item) => item.dataset.prop);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
requiredProps.value = {};
|
||||
@@ -831,11 +834,9 @@ async function selectAdviceBase(key, row) {
|
||||
});
|
||||
}
|
||||
|
||||
// 将选中的基础项“覆盖”到当前处方行(这是之前正常工作的核心逻辑)
|
||||
prescriptionList.value[rowIndex.value] = {
|
||||
...prescriptionList.value[rowIndex.value],
|
||||
...JSON.parse(JSON.stringify(row)),
|
||||
};
|
||||
// 将选中的基础项“覆盖”到当前处方行
|
||||
// 用 Object.assign 原地修改,确保 vxe-table 能检测到变更重新渲染
|
||||
Object.assign(prescriptionList.value[rowIndex.value], JSON.parse(JSON.stringify(row)));
|
||||
|
||||
// 后续字段处理保持原样
|
||||
// 🔧 修复执行科室逻辑:诊疗项目优先使用项目维护的所属科室(row.orgId)
|
||||
@@ -1271,7 +1272,7 @@ function handleSaveSign(row, index) {
|
||||
return;
|
||||
}
|
||||
isSaving.value = true; // #437 立即加锁,消除 TOCTOU 竞态
|
||||
proxy.$refs['formRef' + index].validate((valid) => {
|
||||
proxy.$refs['editFormRef'].validate((valid) => {
|
||||
if (!valid) {
|
||||
isSaving.value = false; // 验证失败释放锁
|
||||
return;
|
||||
@@ -1391,6 +1392,14 @@ defineExpose({ getListInfo, closeAllPopovers });
|
||||
:deep(.vxe-table--expand-btn) {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
// 编辑表单卡片:独立于表格,显示在表格下方
|
||||
.edit-form-card {
|
||||
margin-top: 12px;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
}
|
||||
.medicine-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<div>
|
||||
<el-row :gutter="24">
|
||||
<el-col
|
||||
@@ -873,90 +873,66 @@ function handleInfectiousDiseaseReport() {
|
||||
// 疾病名称到报卡编码的映射(根据传染病报告卡弹窗中的疾病列表)
|
||||
const diseaseNameToCode = {
|
||||
// 甲类
|
||||
'鼠疫': '0101',
|
||||
'霍乱': '0102',
|
||||
'鼠疫': '0101', '霍乱': '0102',
|
||||
// 乙类
|
||||
'传染性非典型肺炎': '0201',
|
||||
'艾滋病': '0202',
|
||||
'病毒性肝炎': '0203',
|
||||
'脊髓灰质炎': '0204',
|
||||
'人感染高致病性禽流感': '0205',
|
||||
'麻疹': '0206',
|
||||
'流行性出血热': '0207',
|
||||
'狂犬病': '0208',
|
||||
'流行性乙型脑炎': '0209',
|
||||
'登革热': '0210',
|
||||
'炭疽': '0211',
|
||||
'细菌性和阿米巴性痢疾': '0212',
|
||||
'肺结核': '0213',
|
||||
'伤寒和副伤寒': '0214',
|
||||
'流行性脑脊髓膜炎': '0215',
|
||||
'百日咳': '0216',
|
||||
'白喉': '0217',
|
||||
'新生儿破伤风': '0218',
|
||||
'猩红热': '0219',
|
||||
'布鲁氏菌病': '0220',
|
||||
'淋病': '0221',
|
||||
'梅毒': '0222',
|
||||
'钩端螺旋体病': '0223',
|
||||
'血吸虫病': '0224',
|
||||
'疟疾': '0225',
|
||||
'新型冠状病毒肺炎': '0226',
|
||||
'甲型H1N1流感': '0227',
|
||||
'传染性非典型肺炎': '0201', '艾滋病': '0202', '病毒性肝炎': '0203',
|
||||
'脊髓灰质炎': '0204', '人感染高致病性禽流感': '0205', '麻疹': '0206',
|
||||
'流行性出血热': '0207', '狂犬病': '0208', '流行性乙型脑炎': '0209',
|
||||
'登革热': '0210', '炭疽': '0211', '细菌性和阿米巴性痢疾': '0212',
|
||||
'肺结核': '0213', '伤寒和副伤寒': '0214', '流行性脑脊髓膜炎': '0215',
|
||||
'百日咳': '0216', '白喉': '0217', '新生儿破伤风': '0218',
|
||||
'猩红热': '0219', '布鲁氏菌病': '0220', '淋病': '0221',
|
||||
'梅毒': '0222', '钩端螺旋体病': '0223', '血吸虫病': '0224',
|
||||
'疟疾': '0225', '新型冠状病毒肺炎': '0226', '甲型H1N1流感': '0227',
|
||||
'人感染H7N9禽流感': '0228',
|
||||
// 丙类
|
||||
'流行性感冒': '0301',
|
||||
'流行性腮腺炎': '0302',
|
||||
'风疹': '0303',
|
||||
'急性出血性结膜炎': '0304',
|
||||
'麻风病': '0305',
|
||||
'流行性和地方性斑疹伤寒': '0306',
|
||||
'黑热病': '0307',
|
||||
'包虫病': '0308',
|
||||
'丝虫病': '0309',
|
||||
'流行性感冒': '0301', '流行性腮腺炎': '0302', '风疹': '0303',
|
||||
'急性出血性结膜炎': '0304', '麻风病': '0305',
|
||||
'流行性和地方性斑疹伤寒': '0306', '黑热病': '0307',
|
||||
'包虫病': '0308', '丝虫病': '0309',
|
||||
'除霍乱/菌痢/伤寒副伤寒以外的感染性腹泻病': '0310',
|
||||
'其它感染性腹泻病': '0310',
|
||||
'手足口病': '0311',
|
||||
'其它感染性腹泻病': '0310', '手足口病': '0311',
|
||||
};
|
||||
|
||||
// 获取所有需要触发传染病报卡的诊断,但跳过已有已提交报卡的诊断
|
||||
// 判断依据:1) 硬编码名称匹配;2) 后端配置了 reportTypeCode(报卡类型)
|
||||
const infectiousDiagnoses = form.value.diagnosisList
|
||||
.map(d => {
|
||||
// 跳过已有已提交报卡的诊断
|
||||
if (d.hasInfectiousReport === 1) return null;
|
||||
// 获取所有需要触发传染病报卡的诊断,跳过已有已提交报卡的诊断
|
||||
const infectiousDiagnoses = [];
|
||||
|
||||
let diseaseCode = null;
|
||||
for (const d of form.value.diagnosisList) {
|
||||
// 跳过已有已提交报卡的诊断
|
||||
if (d.hasInfectiousReport === 1) continue;
|
||||
|
||||
// 1. 尝试精确名称匹配
|
||||
if (d.name && diseaseNameToCode[d.name]) {
|
||||
diseaseCode = diseaseNameToCode[d.name];
|
||||
}
|
||||
// 2. 尝试部分名称匹配(如"古典生物型霍乱"包含"霍乱")
|
||||
else if (d.name && d.reportTypeCode) {
|
||||
const match = Object.entries(diseaseNameToCode).find(([name]) =>
|
||||
name && d.name.includes(name)
|
||||
);
|
||||
if (match) {
|
||||
diseaseCode = match[1];
|
||||
}
|
||||
}
|
||||
// 3. 配置了 reportTypeCode 但无名称匹配,仍触发弹窗(不预选疾病)
|
||||
else if (d.reportTypeCode) {
|
||||
let diseaseCode = null;
|
||||
|
||||
// 1. 精确名称匹配硬编码映射表
|
||||
if (d.name && diseaseNameToCode[d.name]) {
|
||||
diseaseCode = diseaseNameToCode[d.name];
|
||||
}
|
||||
// 2. 部分名称匹配(双向:诊断名包含映射key,或映射key包含诊断名)
|
||||
else if (d.name && d.reportTypeCode) {
|
||||
const match = Object.entries(diseaseNameToCode).find(([name]) =>
|
||||
name && (d.name.includes(name) || name.includes(d.name))
|
||||
);
|
||||
if (match) {
|
||||
diseaseCode = match[1];
|
||||
} else {
|
||||
// 3. 诊断目录中配置了报卡类型(reportTypeCode)但无名称匹配,仍触发弹窗
|
||||
diseaseCode = 'OTHER';
|
||||
}
|
||||
}
|
||||
// 4. 仅有reportTypeCode但name为空
|
||||
else if (d.reportTypeCode) {
|
||||
diseaseCode = 'OTHER';
|
||||
}
|
||||
|
||||
if (!diseaseCode) return null;
|
||||
return { diagnosis: d, diseaseCode };
|
||||
})
|
||||
.filter(item => item !== null);
|
||||
if (diseaseCode) {
|
||||
infectiousDiagnoses.push({ diagnosis: d, diseaseCode });
|
||||
}
|
||||
}
|
||||
|
||||
if (infectiousDiagnoses.length === 0) return;
|
||||
|
||||
const allSelectedDiseases = infectiousDiagnoses.map(item => item.diseaseCode);
|
||||
|
||||
if (allSelectedDiseases.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 优先使用命中传染病映射的主诊断,否则使用第一条命中的传染病诊断
|
||||
const mainInfectiousDiagnosis = infectiousDiagnoses.find(item => item.diagnosis.maindiseFlag === 1)?.diagnosis;
|
||||
const firstInfectiousDiagnosis = infectiousDiagnoses[0].diagnosis;
|
||||
|
||||
@@ -1738,7 +1738,7 @@ const loadCategoryItems = async (categoryKey, loadMore = false) => {
|
||||
const mappedItems = records.map(item => {
|
||||
// 套餐项目处理:需同时满足 feePackageId 有效且 packageName 非空
|
||||
// BugFix#556: 增加 packageName 联合判断,避免普通项目因 feePackageId 有值被误标为套餐
|
||||
const isPackage = item.feePackageId != null && item.feePackageId !== '' && item.feePackageId !== 'null' && item.packageName
|
||||
const isPackage = Boolean(item.feePackageId != null && item.feePackageId !== '' && item.feePackageId !== 'null' && item.packageName)
|
||||
const itemPrice = isPackage
|
||||
? (parseFloat(item.packageAmount || 0) || parseFloat(item.retailPrice || 0) || parseFloat(item.price || 0))
|
||||
: (parseFloat(item.retailPrice || 0) || parseFloat(item.price || 0))
|
||||
@@ -2226,7 +2226,7 @@ const handleSave = () => {
|
||||
// Bug #326修复: 传入 activityId,后端直接使用 ID 关联,避免用名称反查
|
||||
activityId: item.activityId || item.itemId || null,
|
||||
feePackageId: item.feePackageId || null,
|
||||
isPackage: item.isPackage || false,
|
||||
isPackage: Boolean(item.isPackage),
|
||||
sampleType: item.sampleType || '',
|
||||
unit: item.unit || ''
|
||||
}))
|
||||
|
||||
@@ -636,13 +636,14 @@ const inputRefs = ref({}); // 存储输入框实例
|
||||
const requiredProps = ref([]); // 存储必填项 prop 顺序
|
||||
const totalAmount = ref(0);
|
||||
const tcmDianosis = ref();
|
||||
const { method_code, unit_code, rate_code, distribution_category_code, dosage_instruction } =
|
||||
const { method_code, unit_code, rate_code, distribution_category_code, dosage_instruction, method_of_decocting_medicine } =
|
||||
proxy.useDict(
|
||||
'method_code',
|
||||
'unit_code',
|
||||
'rate_code',
|
||||
'distribution_category_code',
|
||||
'dosage_instruction'
|
||||
'dosage_instruction',
|
||||
'method_of_decocting_medicine'
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
|
||||
@@ -198,11 +198,23 @@
|
||||
align="center"
|
||||
min-width="100"
|
||||
/>
|
||||
<!-- <vxe-column title="操作" min-width="100" align="center" fixed="right">
|
||||
<vxe-column
|
||||
title="操作"
|
||||
min-width="100"
|
||||
align="center"
|
||||
fixed="right"
|
||||
>
|
||||
<template #default="scope">
|
||||
<el-button link type="primary" size="small">补打</el-button>
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="handlePrint(scope.row)"
|
||||
>
|
||||
打印
|
||||
</el-button>
|
||||
</template>
|
||||
</vxe-column> -->
|
||||
</vxe-column>
|
||||
</vxe-table>
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
@@ -238,6 +250,7 @@
|
||||
|
||||
<script setup>
|
||||
import {nextTick, ref} from 'vue';
|
||||
import {simplePrint, PRINT_TEMPLATE} from '@/utils/printUtils';
|
||||
import {getDepositInfo, getDepositInfoPage} from './components/api';
|
||||
import PatientList from './components/patientList.vue';
|
||||
import ChargeDialog from './components/chargeDialog.vue';
|
||||
@@ -319,6 +332,36 @@ function refund() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印预交金收据
|
||||
*
|
||||
* @param {Object} row 当前行数据
|
||||
*/
|
||||
async function handlePrint(row) {
|
||||
if (!patientInfo.value.patientId) {
|
||||
proxy.$modal.msgError("请先选择病人!");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const printData = {
|
||||
patientName: patientInfo.value.patientName || "",
|
||||
encounterNosd: patientInfo.value.busNo || "",
|
||||
inHospitalOrgName: patientInfo.value.inHospitalOrgName || "",
|
||||
patientId: patientInfo.value.patientId || "",
|
||||
contractName: patientInfo.value.contractName || "",
|
||||
currentTime: row.operateTime || new Date().toLocaleString(),
|
||||
balanceAmount: row.tenderedAmount ? row.tenderedAmount.toFixed(2) : "0.00",
|
||||
amountInWords: "",
|
||||
paymentDetails: "收据号: " + (row.paymentNo || ""),
|
||||
};
|
||||
await simplePrint(PRINT_TEMPLATE.ADVANCE_PAYMENT, printData);
|
||||
proxy.$modal.msgSuccess("打印成功");
|
||||
} catch (error) {
|
||||
console.error("预交金打印失败:", error);
|
||||
proxy.$modal.msgError("打印失败: " + (error.message || "未知错误"));
|
||||
}
|
||||
}
|
||||
|
||||
/** 选择病人 */
|
||||
function handlePatientSelected(row) {
|
||||
// console.log(row, 'rowwwwwwwwhandlePatientSelected');
|
||||
|
||||
@@ -18,17 +18,13 @@
|
||||
查询
|
||||
</el-button>
|
||||
</el-space>
|
||||
<el-space>
|
||||
<!-- <el-button>读卡</el-button> -->
|
||||
<!-- <el-button type="primary">无档登记</el-button> -->
|
||||
</el-space>
|
||||
</div>
|
||||
<div class="table-container">
|
||||
<vxe-table
|
||||
:data="treatHospitalizedData"
|
||||
style="width: 100%"
|
||||
height="100%"
|
||||
show-overflow
|
||||
show-overflow="title"
|
||||
>
|
||||
<vxe-column
|
||||
type="seq"
|
||||
@@ -104,20 +100,68 @@
|
||||
align="center"
|
||||
title="登记员"
|
||||
/>
|
||||
<vxe-column
|
||||
align="center"
|
||||
title="登记状态"
|
||||
width="100"
|
||||
>
|
||||
<template #default="scope">
|
||||
<span :style="{ color: scope.row.statusEnum == 8 ? '#F56C6C' : '#67C23A' }">
|
||||
{{ scope.row.statusEnum == 8 ? '已作废' : '已登记' }}
|
||||
</span>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column
|
||||
fixed="right"
|
||||
align="center"
|
||||
title="操作"
|
||||
width="88"
|
||||
width="280"
|
||||
>
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
type="primary"
|
||||
text
|
||||
@click="doEdit(scope.row)"
|
||||
@click="doView(scope.row)"
|
||||
>
|
||||
查看
|
||||
</el-button>
|
||||
<el-tooltip
|
||||
v-if="scope.row.statusEnum == 5"
|
||||
content="患者已入科接收,无法修改登记信息"
|
||||
placement="top"
|
||||
>
|
||||
<el-button
|
||||
type="primary"
|
||||
text
|
||||
disabled
|
||||
>
|
||||
修改
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
<el-button
|
||||
v-else-if="scope.row.statusEnum == 8"
|
||||
type="primary"
|
||||
text
|
||||
disabled
|
||||
>
|
||||
修改
|
||||
</el-button>
|
||||
<el-button
|
||||
v-else
|
||||
type="primary"
|
||||
text
|
||||
@click="doModify(scope.row)"
|
||||
>
|
||||
修改
|
||||
</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
text
|
||||
:disabled="scope.row.statusEnum == 5 || scope.row.statusEnum == 8"
|
||||
@click="doVoid(scope.row)"
|
||||
>
|
||||
作废
|
||||
</el-button>
|
||||
</template>
|
||||
</vxe-column>
|
||||
</vxe-table>
|
||||
@@ -134,35 +178,32 @@
|
||||
v-model:dialog-visible="patientRegisterVisible"
|
||||
:patient-info="patient"
|
||||
:in-hospital-info="inHospitalInfo"
|
||||
title="登记"
|
||||
:title="dialogTitle"
|
||||
:registration-type="registrationType"
|
||||
:already-edit="alreadyEdit"
|
||||
:no-file="noFile"
|
||||
:is-registered="true"
|
||||
:is-registered="!isEditMode"
|
||||
:is-edit-mode="isEditMode"
|
||||
@ok-act="patientRegisterOK"
|
||||
@cancel-act="cancelAct"
|
||||
/>
|
||||
</template>
|
||||
<script setup>
|
||||
import PatientRegister from './patientRegister.vue';
|
||||
import {getAdmissionPage, getContractList, getInHospitalInfo, getPatientBasicInfo} from './api';
|
||||
import {ElMessage, ElMessageBox} from 'element-plus';
|
||||
import {getAdmissionPage, getContractList, getInHospitalInfo, getPatientBasicInfo, voidRegistration} from './api';
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
const { admit_source_code } = proxy.useDict('admit_source_code');
|
||||
//const { proxy } = getCurrentInstance();
|
||||
const emits = defineEmits([]);
|
||||
// const props = defineProps({});
|
||||
const searchForm = reactive({
|
||||
searchType: 'name',
|
||||
searchKey: '',
|
||||
});
|
||||
const total = ref();
|
||||
const inHospitalInfo = ref({});
|
||||
const alreadyEdit = ref(true);
|
||||
const isEditMode = ref(false);
|
||||
const dialogTitle = ref('登记');
|
||||
const queryParams = ref({
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
searchKey: undefined,
|
||||
registeredFlag: '1',
|
||||
searchKey: '',
|
||||
});
|
||||
@@ -173,22 +214,58 @@ const noFile = ref(false);
|
||||
const registrationType = ref(true);
|
||||
const patient = ref({});
|
||||
const priceTypeList = ref({});
|
||||
const doEdit = (row) => {
|
||||
getPatientBasicInfo(row.patientId).then((res) => {
|
||||
patient.value = res.data;
|
||||
});
|
||||
getInHospitalInfo(row.encounterId).then((res) => {
|
||||
inHospitalInfo.value = res.data;
|
||||
patientRegisterVisible.value = true;
|
||||
noFile.value = false;
|
||||
});
|
||||
const doView = async (row) => {
|
||||
isEditMode.value = false;
|
||||
dialogTitle.value = '查看';
|
||||
const [patientRes, hospitalRes] = await Promise.all([
|
||||
getPatientBasicInfo(row.patientId),
|
||||
getInHospitalInfo(row.encounterId),
|
||||
]);
|
||||
patient.value = patientRes.data;
|
||||
inHospitalInfo.value = hospitalRes.data;
|
||||
patientRegisterVisible.value = true;
|
||||
noFile.value = false;
|
||||
};
|
||||
|
||||
const doModify = async (row) => {
|
||||
isEditMode.value = true;
|
||||
dialogTitle.value = '修改登记';
|
||||
const [patientRes, hospitalRes] = await Promise.all([
|
||||
getPatientBasicInfo(row.patientId),
|
||||
getInHospitalInfo(row.encounterId),
|
||||
]);
|
||||
patient.value = patientRes.data;
|
||||
inHospitalInfo.value = hospitalRes.data;
|
||||
patientRegisterVisible.value = true;
|
||||
noFile.value = false;
|
||||
};
|
||||
|
||||
const doVoid = (row) => {
|
||||
ElMessageBox.confirm(
|
||||
'确认作废该患者的住院登记信息吗?作废后不可撤销',
|
||||
'作废确认',
|
||||
{
|
||||
confirmButtonText: '确认',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
}
|
||||
)
|
||||
.then(() => {
|
||||
voidRegistration(row.encounterId).then((res) => {
|
||||
if (res.code == 200) {
|
||||
ElMessage.success('作废成功');
|
||||
getList();
|
||||
} else {
|
||||
ElMessage.error(res.msg || '作废失败');
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch(() => {});
|
||||
};
|
||||
onBeforeMount(() => {});
|
||||
getContract();
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
const activeName = ref('first');
|
||||
|
||||
const patientRegisterOK = () => {
|
||||
patientRegisterVisible.value = false;
|
||||
@@ -211,7 +288,6 @@ function resetQuery() {
|
||||
queryParams.value = {
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
searchKey: undefined,
|
||||
registeredFlag: '1',
|
||||
searchKey: '',
|
||||
};
|
||||
@@ -262,7 +338,6 @@ const getList = () => {
|
||||
}
|
||||
|
||||
treatHospitalizedData.value = dataList;
|
||||
// treatHospitalizedData.value = res.data.records;
|
||||
total.value = res.data.total;
|
||||
});
|
||||
};
|
||||
|
||||
@@ -132,6 +132,23 @@ export function registerInHospital(data) {
|
||||
});
|
||||
}
|
||||
|
||||
// 修改住院登记
|
||||
export function updateRegistration(data) {
|
||||
return request({
|
||||
url: '/inhospital-charge/register/update-registration',
|
||||
method: 'put',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
// 作废住院登记
|
||||
export function voidRegistration(encounterId) {
|
||||
return request({
|
||||
url: `/inhospital-charge/register/void-registration?encounterId=${encounterId}`,
|
||||
method: 'put',
|
||||
});
|
||||
}
|
||||
|
||||
// 无档登记
|
||||
export function noFilesRegister(data) {
|
||||
return request({
|
||||
|
||||
@@ -39,7 +39,10 @@
|
||||
/>
|
||||
</el-scrollbar>
|
||||
<template #footer>
|
||||
<div class="advance-container">
|
||||
<div
|
||||
v-if="!props.isEditMode"
|
||||
class="advance-container"
|
||||
>
|
||||
<div
|
||||
v-if="currentFeeType !== 'hipCash'"
|
||||
class="payment-item"
|
||||
@@ -110,13 +113,21 @@
|
||||
取消
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="!props.isRegistered"
|
||||
v-if="!props.isRegistered && !props.isEditMode"
|
||||
size="fixed"
|
||||
type="primary"
|
||||
@click="handleSubmit"
|
||||
>
|
||||
登记
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="props.isEditMode"
|
||||
size="fixed"
|
||||
type="primary"
|
||||
@click="handleEditSubmit"
|
||||
>
|
||||
保存
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
@@ -125,7 +136,7 @@ const { proxy } = getCurrentInstance();
|
||||
import {ElMessage, ElMessageBox} from 'element-plus';
|
||||
import PatientInfoComp from './patientInfo.vue';
|
||||
import RegisterForm from './registerForm.vue';
|
||||
import {noFilesRegister, registerInHospital} from './api';
|
||||
import {noFilesRegister, registerInHospital, updateRegistration} from './api';
|
||||
import {getInit} from '@/views/doctorstation/components/api';
|
||||
import {useRouter} from 'vue-router';
|
||||
import {wxPay, WxPayResult} from '../../../../charge/cliniccharge/components/api';
|
||||
@@ -161,6 +172,10 @@ const props = defineProps({
|
||||
type: Boolean,
|
||||
default: false, // false 表示待登记,true 表示已登记
|
||||
},
|
||||
isEditMode: {
|
||||
type: Boolean,
|
||||
default: false, // true 表示修改已登记的记录
|
||||
},
|
||||
});
|
||||
|
||||
watch(
|
||||
@@ -283,6 +298,7 @@ const handleSubmit = () => {
|
||||
ElMessage.success(res.msg);
|
||||
// 打印预交金收据
|
||||
printDepositReceipt(props.patientInfo, params.inHospitalInfo);
|
||||
emits('okAct');
|
||||
cancelAct();
|
||||
// 询问是否需要医保登记
|
||||
// ElMessageBox.confirm('是否需要进行医保登记?', '医保登记确认', {
|
||||
@@ -392,19 +408,25 @@ const handleSubmit = () => {
|
||||
})
|
||||
.then(() => {
|
||||
console.log('路由跳转成功');
|
||||
emits('okAct');
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('路由跳转失败:', error);
|
||||
ElMessage.error('跳转到医保登记页面失败');
|
||||
emits('okAct');
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('跳转异常:', error);
|
||||
emits('okAct');
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
// 用户取消医保登记,关闭当前弹窗
|
||||
emits('okAct');
|
||||
});
|
||||
} else {
|
||||
// 自费患者,直接通知刷新列表
|
||||
emits('okAct');
|
||||
}
|
||||
cancelAct();
|
||||
} else {
|
||||
@@ -430,6 +452,34 @@ const handleSubmit = () => {
|
||||
}
|
||||
};
|
||||
|
||||
/* 修改登记 */
|
||||
const handleEditSubmit = () => {
|
||||
RegisterFormRef.value.validateData(async () => {
|
||||
const formData = RegisterFormRef.value.submitForm;
|
||||
const params = {
|
||||
encounterId: props.inHospitalInfo.encounterId,
|
||||
patientId: props.patientInfo.patientId,
|
||||
inHospitalOrgId: formData.inHospitalOrgId,
|
||||
wardLocationId: formData.wardLocationId,
|
||||
priorityEnum: formData.priorityEnum,
|
||||
admitSourceCode: formData.admitSourceCode,
|
||||
inWayCode: formData.inWayCode,
|
||||
startTime: formData.startTime,
|
||||
contractNo: formData.contractNo,
|
||||
typeCoce: formData.typeCoce,
|
||||
};
|
||||
updateRegistration(params).then((res) => {
|
||||
if (res.code == 200) {
|
||||
ElMessage.success(res.msg);
|
||||
emits('okAct');
|
||||
cancelAct();
|
||||
} else {
|
||||
ElMessage.error(res.msg);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const openAct = () => {
|
||||
console.log(props.patientInfo, 'patientRegister.vue');
|
||||
console.log(props.inHospitalInfo, 'inHospitalInfo.vue');
|
||||
|
||||
@@ -364,7 +364,7 @@ const medicalInsuranceTitle = ref('');
|
||||
// });
|
||||
const getProvincesAndCitiesInfo = async () => {
|
||||
try {
|
||||
if (inHospitalInfo.encounterId) {
|
||||
if (props.inHospitalInfo.encounterId) {
|
||||
const res = await getProvincesAndCities(props.inHospitalInfo.encounterId);
|
||||
// console.log('获取省市医保字符串', res);
|
||||
if (res && res.code == 200) {
|
||||
@@ -388,8 +388,7 @@ watch(
|
||||
if (newEncounterId) {
|
||||
getProvincesAndCitiesInfo();
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
}
|
||||
);
|
||||
|
||||
/* 提交表单 */
|
||||
@@ -463,8 +462,8 @@ watch(
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
getInitOptions();
|
||||
onMounted(async () => {
|
||||
await getInitOptions();
|
||||
setValue();
|
||||
setDefaultAdmitSource();
|
||||
if (submitForm.inHospitalOrgId) {
|
||||
@@ -505,7 +504,7 @@ function getInitOptions() {
|
||||
// 获取所有病区
|
||||
const wardPromise = getPractitionerWard();
|
||||
|
||||
Promise.all([orgPromise, wardPromise]).then(([orgRes, wardRes]) => {
|
||||
const initPromise = Promise.all([orgPromise, wardPromise]).then(([orgRes, wardRes]) => {
|
||||
// 入院科室:展示所有 typeEnum=2(科室) + classEnum含"2"(住院) 的科室
|
||||
organization.value = orgRes.data.records.filter(
|
||||
(record) => record.typeEnum === 2 && checkClassEnumValue(record.classEnum, 2)
|
||||
@@ -529,19 +528,15 @@ function getInitOptions() {
|
||||
}
|
||||
});
|
||||
|
||||
// if (!props.noFile) {
|
||||
// wardList().then((res) => {
|
||||
// wardListOptions.value = res.data;
|
||||
// });
|
||||
// }
|
||||
diagnosisInit().then((res) => {
|
||||
verificationStatusOptions.value = res.data.verificationStatusOptions;
|
||||
});
|
||||
getContractList().then((response) => {
|
||||
contractList.value = response.data;
|
||||
setValue();
|
||||
});
|
||||
getDiagnosisInfo(undefined);
|
||||
|
||||
return initPromise;
|
||||
}
|
||||
function getDiagnosisInfo(value) {
|
||||
getDiagnosisDefinitionList({ pageSize: 500, pageNo: 1, searchKey: value }).then((res) => {
|
||||
@@ -550,6 +545,7 @@ function getDiagnosisInfo(value) {
|
||||
}
|
||||
|
||||
function handleNodeClick(orgInfo) {
|
||||
const savedWardId = props.inHospitalInfo?.wardLocationId; // 保存原始病区ID,用于编辑模式恢复
|
||||
submitForm.wardLocationId = undefined; // 切换科室时,先清空原有病区
|
||||
submitForm.totalBedsNum = undefined;
|
||||
submitForm.idleBedsNum = undefined;
|
||||
@@ -558,13 +554,20 @@ function handleNodeClick(orgInfo) {
|
||||
wardList({ orgId: orgInfo.id })
|
||||
.then((res) => {
|
||||
wardListOptions.value = res.data || [];
|
||||
if (wardListOptions.value.length > 0 && !props.inHospitalInfo.wardLocationId) {
|
||||
submitForm.wardLocationId = wardListOptions.value[0].id;
|
||||
const defaultWard = wardListOptions.value.find(
|
||||
(item) => item.id === submitForm.wardLocationId
|
||||
);
|
||||
if (defaultWard) {
|
||||
handleWardClick(defaultWard);
|
||||
if (wardListOptions.value.length > 0) {
|
||||
// 编辑模式:尝试恢复之前保存的病区
|
||||
if (savedWardId) {
|
||||
const savedWard = wardListOptions.value.find((item) => String(item.id) === String(savedWardId));
|
||||
if (savedWard) {
|
||||
submitForm.wardLocationId = savedWardId;
|
||||
handleWardClick(savedWard);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// 新增模式 或 原病区不在新科室下:自动选中第一个病区
|
||||
if (!submitForm.wardLocationId) {
|
||||
submitForm.wardLocationId = wardListOptions.value[0].id;
|
||||
handleWardClick(wardListOptions.value[0]);
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -619,6 +622,19 @@ function setValue() {
|
||||
submitForm.inWayCode_dictText = props.inHospitalInfo?.inWayCode_dictText;
|
||||
}
|
||||
|
||||
// 编辑模式下,API 数据异步到达后重新赋值表单字段并加载病区
|
||||
watch(
|
||||
() => props.inHospitalInfo.encounterId,
|
||||
(newEncounterId, oldEncounterId) => {
|
||||
if (newEncounterId && newEncounterId !== oldEncounterId) {
|
||||
setValue();
|
||||
if (submitForm.inHospitalOrgId) {
|
||||
handleNodeClick({ id: submitForm.inHospitalOrgId });
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const registerRef = ref();
|
||||
/* 登记 */
|
||||
const validateData = async (callback) => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<el-form :model="row" :rules="rules" :ref="(el) => (formRef = el)" :label-width="100">
|
||||
<div class="expend_div" style="padding: 16px; background: #f8f9fa; border-radius: 8px">
|
||||
<template v-if="row.adviceType == 1">
|
||||
@@ -71,7 +71,17 @@
|
||||
/>
|
||||
</el-form-item>
|
||||
<span class="medicine-info"> 诊断:{{ config.diagnosisName }} </span>
|
||||
<span class="medicine-info"> 皮试:{{ row.skinTestFlag_enumText }} </span>
|
||||
<span class="medicine-info">
|
||||
皮试:
|
||||
<el-select
|
||||
v-model="row.skinTestFlag"
|
||||
style="width: 70px"
|
||||
size="small"
|
||||
>
|
||||
<el-option :value="1" label="是" />
|
||||
<el-option :value="0" label="否" />
|
||||
</el-select>
|
||||
</span>
|
||||
<span class="medicine-info"> 注射药品:{{ row.injectFlag_enumText }} </span>
|
||||
<span class="total-amount">
|
||||
总金额:{{ row.totalPrice ? Number(row.totalPrice).toFixed(2) + ' 元' : '0.00 元' }}
|
||||
@@ -467,7 +477,7 @@
|
||||
</el-form-item>
|
||||
<div class="form-group">
|
||||
<el-select
|
||||
v-model="row.lotNumber"
|
||||
v-model="row.inventoryId"
|
||||
style="width: 180px; margin-right: 20px"
|
||||
placeholder="药房"
|
||||
>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<div class="inpatientDoctor-order-container" style="width: 100%">
|
||||
<div style="margin-bottom: 5px" class="order-operate-btn">
|
||||
<div style="height: 44px; display: flex; align-items: center; flex: none">
|
||||
@@ -142,9 +142,9 @@
|
||||
</span>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column title="开嘱医生" align="center" field="createdStaffName" width="120">
|
||||
<vxe-column title="开嘱医生" align="center" field="requesterId_dictText" width="120">
|
||||
<template #default="scope">
|
||||
{{ scope.row.createdStaffName || '-' }}
|
||||
{{ scope.row.requesterId_dictText || '-' }}
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column title="开始时间" align="center" field="startTime" width="200">
|
||||
@@ -268,6 +268,7 @@
|
||||
<el-tag v-else-if="scope.row.statusEnum == 10" type="primary">已校对</el-tag>
|
||||
<el-tag v-else-if="scope.row.statusEnum == 11" type="primary">待接收</el-tag>
|
||||
<el-tag v-else-if="scope.row.statusEnum == 3" type="success">已校对</el-tag>
|
||||
<el-tag v-else-if="scope.row.statusEnum == 13" type="warning">已停嘱</el-tag>
|
||||
<el-tag v-else-if="scope.row.statusEnum == 6" type="danger">停止</el-tag>
|
||||
<el-tag v-else-if="scope.row.statusEnum == 20" type="success">已完成</el-tag>
|
||||
<el-tag v-else type="info">{{ scope.row.chargeStatus_enumText }}</el-tag>
|
||||
@@ -332,14 +333,16 @@
|
||||
<span v-if="!scope.row.isEdit">
|
||||
{{ scope.row.skinTestFlag_enumText || '-' }}
|
||||
</span>
|
||||
<el-checkbox
|
||||
<el-select
|
||||
v-else
|
||||
v-model="scope.row.skinTestFlag"
|
||||
:true-value="true"
|
||||
:false-value="0"
|
||||
style="width: 80px"
|
||||
size="small"
|
||||
@click.stop
|
||||
>
|
||||
是
|
||||
</el-checkbox>
|
||||
<el-option :value="1" label="是" />
|
||||
<el-option :value="0" label="否" />
|
||||
</el-select>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column title="停嘱医生" align="center" field="stopUserName" width="120">
|
||||
@@ -445,12 +448,13 @@ import {
|
||||
} from '../api';
|
||||
import adviceBaseList from '../adviceBaseList';
|
||||
import {calculateQuantityByDays} from '@/utils/his';
|
||||
import {localPatientInfo as patientInfo} from '../../store/localPatient.js';
|
||||
import {localPatientInfo as localPatientInfoRef} from '../../store/localPatient.js';
|
||||
import OrderGroupDrawer from '@/views/doctorstation/components/prescription/orderGroupDrawer.vue';
|
||||
import PrescriptionHistory from '@/views/doctorstation/components/prescription/prescriptionHistory.vue';
|
||||
import Decimal from 'decimal.js';
|
||||
import {ElMessage, ElMessageBox} from 'element-plus';
|
||||
import useUserStore from '@/store/modules/user';
|
||||
import {RequestStatus} from '@/utils/medicalConstants';
|
||||
import ApplicationFormBottomBtn from './applicationForm/applicationFormBottomBtn.vue';
|
||||
import LeaveHospitalDialog from './applicationForm/leaveHospitalDialog.vue';
|
||||
import TransferOrganizationDialog from './applicationForm/transferOrganizationDialog.vue';
|
||||
@@ -515,10 +519,10 @@ const unitMap = ref({
|
||||
unit: 'unit',
|
||||
});
|
||||
const buttonDisabled = computed(() => {
|
||||
return !patientInfo.value;
|
||||
return !localPatientInfoRef.value;
|
||||
});
|
||||
const isSaveDisabled = computed(() => {
|
||||
return !patientInfo.value || prescriptionList.value.length === 0;
|
||||
return !localPatientInfoRef.value || prescriptionList.value.length === 0;
|
||||
});
|
||||
const props = defineProps({
|
||||
patientInfo: {
|
||||
@@ -579,9 +583,10 @@ const adviceTypeList = computed(() => {
|
||||
hasShownPharmacyConfigWarning.value = true;
|
||||
}
|
||||
|
||||
// 只返回不需要取药科室配置的类别(诊疗、手术、出院带药)
|
||||
// 只返回不需要取药科室配置的类别(诊疗、耗材、手术、出院带药)
|
||||
return [
|
||||
{ label: '诊疗', value: 3, adviceType: 3, categoryCode: '' },
|
||||
{ label: '耗材', value: 2, adviceType: 2, categoryCode: '' },
|
||||
{ label: '手术', value: 6, adviceType: 6, categoryCode: '' },
|
||||
{ label: '出院带药', value: 7, adviceType: 7, categoryCode: '' },
|
||||
{ label: '文字', value: 8, adviceType: 8, categoryCode: '' },
|
||||
@@ -608,8 +613,9 @@ const adviceTypeList = computed(() => {
|
||||
typeList.push({ label: '中草药', value: '1-4', adviceType: 1, categoryCode: '4' });
|
||||
}
|
||||
|
||||
// 始终添加诊疗和手术(它们不受取药配置限制)
|
||||
// 始终添加诊疗、耗材和手术(它们不受取药配置限制)
|
||||
typeList.push({ label: '诊疗', value: 3, adviceType: 3, categoryCode: '' });
|
||||
typeList.push({ label: '耗材', value: 2, adviceType: 2, categoryCode: '' });
|
||||
typeList.push({ label: '手术', value: 6, adviceType: 6, categoryCode: '' });
|
||||
|
||||
// 始终添加"出院带药"选项(不需要取药科室配置)
|
||||
@@ -633,6 +639,10 @@ const statusOption = [
|
||||
label: '已签发',
|
||||
value: 2,
|
||||
},
|
||||
{
|
||||
label: '已停嘱',
|
||||
value: 13,
|
||||
},
|
||||
{
|
||||
label: '停止',
|
||||
value: 6,
|
||||
@@ -706,7 +716,7 @@ function getListInfo(addNewRow) {
|
||||
const orgTreePromise = getOrgTree().then((res) => {
|
||||
organization.value = res?.data?.records ?? res?.data ?? [];
|
||||
});
|
||||
getPrescriptionList(patientInfo.value.encounterId).then((res) => {
|
||||
getPrescriptionList(localPatientInfoRef.value.encounterId).then((res) => {
|
||||
// 等待科室树加载完成后再处理处方数据,确保 resolveOrgId 能正确匹配
|
||||
orgTreePromise.then(() => {
|
||||
loading.value = false;
|
||||
@@ -722,6 +732,11 @@ function getListInfo(addNewRow) {
|
||||
return {
|
||||
...parsedContent,
|
||||
...item,
|
||||
// 🔧 修复:确保开嘱医生名称正确显示
|
||||
// 优先使用后端返回的 requesterId_dictText,其次从 userStore 获取
|
||||
requesterId_dictText: item.requesterId_dictText || item.requesterId_dict_text
|
||||
|| (String(item.requesterId) === String(userStore.practitionerId) ? userStore.name : '')
|
||||
|| parsedContent?.requesterId_dictText || '-',
|
||||
// 🔧 修复:contentJson 中的 totalPrice 优先于 charge_item 表的 totalPrice
|
||||
// charge_item.totalPrice 可能为 0 或 null(新建医嘱时),导致总金额显示为 "-"
|
||||
totalPrice: parsedContent?.totalPrice || item.totalPrice,
|
||||
@@ -770,10 +785,10 @@ function getListInfo(addNewRow) {
|
||||
}
|
||||
});
|
||||
}).catch(() => { loading.value = false; });
|
||||
getContract({ encounterId: patientInfo.value.encounterId }).then((res) => {
|
||||
getContract({ encounterId: localPatientInfoRef.value.encounterId }).then((res) => {
|
||||
contractList.value = res.data;
|
||||
});
|
||||
accountId.value = patientInfo.value.accountId;
|
||||
accountId.value = localPatientInfoRef.value.accountId;
|
||||
|
||||
// 加载已配置的药品类别
|
||||
loadConfiguredCategories();
|
||||
@@ -783,7 +798,7 @@ function getListInfo(addNewRow) {
|
||||
* 加载已配置的药品类别
|
||||
*/
|
||||
function loadConfiguredCategories() {
|
||||
const orgId = patientInfo.value?.inHospitalOrgId;
|
||||
const orgId = localPatientInfoRef.value?.inHospitalOrgId;
|
||||
if (!orgId) {
|
||||
isCategoryLoaded.value = true; // 标记已加载(即使没有科室ID)
|
||||
return;
|
||||
@@ -857,7 +872,7 @@ const filterPrescriptionList = computed(() => {
|
||||
});
|
||||
|
||||
function getDiagnosisInfo() {
|
||||
getEncounterDiagnosis(patientInfo.value.encounterId).then((res) => {
|
||||
getEncounterDiagnosis(localPatientInfoRef.value.encounterId).then((res) => {
|
||||
diagnosisList.value = res.data;
|
||||
let diagnosisInfo = diagnosisList.value.filter((item) => {
|
||||
return item.maindiseFlag == 1;
|
||||
@@ -885,13 +900,14 @@ function getRowSelectValue(row) {
|
||||
if (row.adviceType == 7) {
|
||||
return 7;
|
||||
}
|
||||
// 耗材(adviceType=2)直接返回数字值,与 adviceTypeList 中的 value 匹配
|
||||
return row.adviceType;
|
||||
}
|
||||
|
||||
// 新增医嘱
|
||||
function handleAddPrescription() {
|
||||
// 校验是否选中患者
|
||||
if (!patientInfo.value || !patientInfo.value.encounterId) {
|
||||
if (!localPatientInfoRef.value || !localPatientInfoRef.value.encounterId) {
|
||||
proxy.$modal.msgWarning('请先选择患者');
|
||||
return;
|
||||
}
|
||||
@@ -940,9 +956,9 @@ function checkUnit(item, row) {
|
||||
* @returns {boolean} true=通过, false=不通过
|
||||
*/
|
||||
function validateStartTime(startTime) {
|
||||
if (!startTime || !patientInfo.value?.inHospitalTime) return true;
|
||||
if (!startTime || !localPatientInfoRef.value?.inHospitalTime) return true;
|
||||
const startDate = new Date(startTime);
|
||||
const inHospitalDate = new Date(patientInfo.value.inHospitalTime);
|
||||
const inHospitalDate = new Date(localPatientInfoRef.value.inHospitalTime);
|
||||
if (startDate < inHospitalDate) {
|
||||
const pad = (n) => String(n).padStart(2, '0');
|
||||
const d = inHospitalDate;
|
||||
@@ -989,6 +1005,10 @@ function clickRowDb({ row, column, event }) {
|
||||
prescriptionList.value[index] = row;
|
||||
}
|
||||
expandOrder.value = [row.uniqueKey];
|
||||
// VXE Table v4: clearRowExpand 后 expandRowKeys 不再自动响应,需手动调 API 展开
|
||||
if (prescriptionRef.value?.setRowExpand) {
|
||||
prescriptionRef.value.setRowExpand([row], true);
|
||||
}
|
||||
} else {
|
||||
proxy.$modal.msgWarning('仅待保存或待签发医嘱允许编辑');
|
||||
}
|
||||
@@ -1181,12 +1201,22 @@ function selectAdviceBase(key, row) {
|
||||
// 用户点击"是",设置皮试标志为"是"
|
||||
prescriptionList.value[rowIndex.value].skinTestFlag = 1;
|
||||
prescriptionList.value[rowIndex.value].skinTestFlag_enumText = '是';
|
||||
expandOrder.value = [currentUniqueKey];
|
||||
const expandRow = filterPrescriptionList.value.find(item => item.uniqueKey === currentUniqueKey);
|
||||
if (expandRow && prescriptionRef.value?.setRowExpand) {
|
||||
prescriptionRef.value.setRowExpand([expandRow], true);
|
||||
}
|
||||
expandOrderAndFocus(currentUniqueKey, row);
|
||||
})
|
||||
.catch((action) => {
|
||||
// 用户点击"否",设置皮试标志为"否"
|
||||
prescriptionList.value[rowIndex.value].skinTestFlag = 0;
|
||||
prescriptionList.value[rowIndex.value].skinTestFlag_enumText = '否';
|
||||
expandOrder.value = [currentUniqueKey];
|
||||
const expandRow = filterPrescriptionList.value.find(item => item.uniqueKey === currentUniqueKey);
|
||||
if (expandRow && prescriptionRef.value?.setRowExpand) {
|
||||
prescriptionRef.value.setRowExpand([expandRow], true);
|
||||
}
|
||||
expandOrderAndFocus(currentUniqueKey, row);
|
||||
});
|
||||
} else {
|
||||
@@ -1432,9 +1462,9 @@ function handleSave() {
|
||||
// 签发处理逻辑
|
||||
function executeSaveLogic() {
|
||||
saveList.forEach((item) => {
|
||||
item.patientId = patientInfo.value.patientId;
|
||||
item.encounterId = patientInfo.value.encounterId;
|
||||
item.accountId = patientInfo.value.accountId;
|
||||
item.patientId = localPatientInfoRef.value.patientId;
|
||||
item.encounterId = localPatientInfoRef.value.encounterId;
|
||||
item.accountId = localPatientInfoRef.value.accountId;
|
||||
item.dbOpType = '1';
|
||||
// Bug #589: 出院带药保存时转为药品类型
|
||||
if (item.adviceType == 7) {
|
||||
@@ -1463,11 +1493,11 @@ function handleSave() {
|
||||
// 保存签发按钮
|
||||
isSaving.value = true;
|
||||
console.log('签发处方参数:', {
|
||||
organizationId: patientInfo.value.inHospitalOrgId,
|
||||
organizationId: localPatientInfoRef.value.inHospitalOrgId,
|
||||
adviceSaveList: list,
|
||||
});
|
||||
savePrescriptionSign({
|
||||
organizationId: patientInfo.value.inHospitalOrgId,
|
||||
organizationId: localPatientInfoRef.value.inHospitalOrgId,
|
||||
regAdviceSaveList: list,
|
||||
})
|
||||
.then((res) => {
|
||||
@@ -1529,8 +1559,8 @@ function handleOrderBindInfo(bindIdInfo) {
|
||||
const newRow = {
|
||||
...prescriptionList.value[rowIndex.value],
|
||||
uniqueKey: nextId.value++,
|
||||
patientId: patientInfo.value.patientId,
|
||||
encounterId: patientInfo.value.encounterId,
|
||||
patientId: localPatientInfoRef.value.patientId,
|
||||
encounterId: localPatientInfoRef.value.encounterId,
|
||||
accountId: accountId.value,
|
||||
quantity: item.quantity,
|
||||
methodCode: item.methodCode,
|
||||
@@ -1633,8 +1663,8 @@ function handleSaveSign(row, index) {
|
||||
|
||||
// 执行保存
|
||||
row.contentJson = undefined;
|
||||
row.patientId = patientInfo.value.patientId;
|
||||
row.encounterId = patientInfo.value.encounterId;
|
||||
row.patientId = localPatientInfoRef.value.patientId;
|
||||
row.encounterId = localPatientInfoRef.value.encounterId;
|
||||
row.accountId = accountId.value;
|
||||
|
||||
// 🔧 文字医嘱(type=8):跳过计费逻辑,总金额为0
|
||||
@@ -1679,6 +1709,7 @@ function handleSaveSign(row, index) {
|
||||
const originalAdviceType = row.adviceType;
|
||||
if (row.adviceType == 7) {
|
||||
row.adviceType = 1;
|
||||
row.prescriptionCategory = 3; // 出院带药标记,与 handleSaveBatch/handleSave 保持一致
|
||||
}
|
||||
row.conditionId = conditionId.value;
|
||||
// 处理总量为小单位情况,需要把单价也保存成小单位的
|
||||
@@ -1705,6 +1736,10 @@ function handleSaveSign(row, index) {
|
||||
: 0;
|
||||
row.skinTestFlag_enumText = row.skinTestFlag == 1 ? '是' : '否';
|
||||
row.contentJson = JSON.stringify(row);
|
||||
// Bug #589: contentJson 已序列化(含 adviceType=1),恢复内存中的出院带药类型显示
|
||||
if (originalAdviceType == 7) {
|
||||
row.adviceType = 7;
|
||||
}
|
||||
if (row.requestId) {
|
||||
row.dbOpType = '2';
|
||||
savePrescription({ regAdviceSaveList: [row] }).then((res) => {
|
||||
@@ -1870,14 +1905,16 @@ function setValue(row) {
|
||||
...prevRow,
|
||||
...baseRow,
|
||||
uniqueKey: currentUniqueKey, // 确保 uniqueKey 不被覆盖
|
||||
// Bug #589: 出院带药在 baseRow 中被药品的 adviceType=1 覆盖,此处恢复
|
||||
adviceType: prevRow.dischargeFlag ? 7 : baseRow.adviceType,
|
||||
// 🔧 修复执行科室逻辑:
|
||||
// 1. 非诊疗类型(adviceType!=3)不需要执行科室,设为undefined
|
||||
// 2. 诊疗类型优先使用项目维护的所属科室(row.orgId),其次positionId
|
||||
// 3. 如果都为空,回退到患者当前所在科室(patientInfo.orgId)
|
||||
// 4. 使用 resolveOrgId 从组织树中匹配正确的 String id,解决大 Long 精度丢失问题
|
||||
orgId: row.adviceType != 3 ? undefined : (resolveOrgId(row.orgId || row.positionId || patientInfo.value?.inHospitalOrgId) || ''),
|
||||
orgId: row.adviceType != 3 ? undefined : (resolveOrgId(row.orgId || row.positionId || localPatientInfoRef.value?.inHospitalOrgId) || ''),
|
||||
// 🔧 修复:同时保存 orgName,当 orgId 在科室树中匹配不到时作为兜底显示
|
||||
orgName: row.adviceType != 3 ? undefined : (findOrgName(row.orgId || row.positionId || patientInfo.value?.inHospitalOrgId) || row.orgName || patientInfo.value?.inHospitalOrgName || ''),
|
||||
orgName: row.adviceType != 3 ? undefined : (findOrgName(row.orgId || row.positionId || localPatientInfoRef.value?.inHospitalOrgId) || row.orgName || localPatientInfoRef.value?.inHospitalOrgName || ''),
|
||||
// dose: undefined, Removed to preserve dose value from group package
|
||||
unitCodeList: unitCodeList.value,
|
||||
doseUnitCode: row.doseUnitCode,
|
||||
@@ -1981,8 +2018,8 @@ function handleSaveGroup(orderGroupList) {
|
||||
// 创建新的处方项目
|
||||
const newRow = {
|
||||
...prescriptionList.value[tempIndex],
|
||||
patientId: patientInfo.value.patientId,
|
||||
encounterId: patientInfo.value.encounterId,
|
||||
patientId: localPatientInfoRef.value.patientId,
|
||||
encounterId: localPatientInfoRef.value.encounterId,
|
||||
accountId: accountId.value,
|
||||
// 🔧 修复 Bug #403:从 mergedDetail 读取明细字段,而非直接从 item 取
|
||||
// item.dose 等字段可能为 null,mergedDetail 已做 ?? 兜底
|
||||
@@ -1996,9 +2033,9 @@ function handleSaveGroup(orderGroupList) {
|
||||
unitCode: mergedDetail.unitCode ?? item.unitCode,
|
||||
unitCode_dictText: item.unitCodeName || mergedDetail.unitCodeName || '',
|
||||
statusEnum: 1,
|
||||
orgId: resolveOrgId(mergedDetail.orgId || patientInfo.value?.inHospitalOrgId) || '',
|
||||
orgId: resolveOrgId(mergedDetail.orgId || localPatientInfoRef.value?.inHospitalOrgId) || '',
|
||||
// 🔧 修复:同时存储 orgName,确保树匹配不到时仍有中文名称可显示
|
||||
orgName: findOrgName(mergedDetail.orgId || patientInfo.value?.inHospitalOrgId) || mergedDetail.orgName || patientInfo.value?.inHospitalOrgName || '',
|
||||
orgName: findOrgName(mergedDetail.orgId || localPatientInfoRef.value?.inHospitalOrgId) || mergedDetail.orgName || localPatientInfoRef.value?.inHospitalOrgName || '',
|
||||
startTime: mergedDetail.startTime || defaultStartTimeFn(),
|
||||
dbOpType: prescriptionList.value[tempIndex].requestId ? '2' : '1',
|
||||
conditionId: conditionId.value,
|
||||
@@ -2040,8 +2077,8 @@ function handleSaveGroup(orderGroupList) {
|
||||
function handleSaveHistory(value) {
|
||||
let saveRow = {
|
||||
...value,
|
||||
patientId: patientInfo.value.patientId,
|
||||
encounterId: patientInfo.value.encounterId,
|
||||
patientId: localPatientInfoRef.value.patientId,
|
||||
encounterId: localPatientInfoRef.value.encounterId,
|
||||
accountId: accountId.value,
|
||||
uniqueKey: undefined,
|
||||
startTime: defaultStartTimeFn(),
|
||||
@@ -2203,10 +2240,10 @@ function handleStopAdvice() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 找出停嘱的
|
||||
// 找出停嘱的(已停止=6 或 已停嘱=13 的不允许再停)
|
||||
for (let index = 0; index < selectRows.length; index++) {
|
||||
const item = selectRows[index];
|
||||
if (item.statusEnum == 6) {
|
||||
if (item.statusEnum == 6 || item.statusEnum == 13) {
|
||||
isStop = false;
|
||||
break;
|
||||
}
|
||||
@@ -2265,9 +2302,9 @@ function confirmStopAdvice() {
|
||||
return;
|
||||
}
|
||||
// 校验:停嘱时间不能早于患者入院时间
|
||||
if (patientInfo.value?.inHospitalTime) {
|
||||
if (localPatientInfoRef.value?.inHospitalTime) {
|
||||
const stopDate = new Date(stopForm.stopTime);
|
||||
const inHospitalDate = new Date(patientInfo.value.inHospitalTime);
|
||||
const inHospitalDate = new Date(localPatientInfoRef.value.inHospitalTime);
|
||||
if (stopDate < inHospitalDate) {
|
||||
const pad = (n) => String(n).padStart(2, '0');
|
||||
const d = inHospitalDate;
|
||||
@@ -2310,11 +2347,11 @@ function handleResumeAdvice() {
|
||||
});
|
||||
return;
|
||||
}
|
||||
// 校验:只有状态为"停止"(statusEnum=6)的医嘱才能恢复
|
||||
// 校验:只有状态为"停止"(statusEnum=6)或"已停嘱"(statusEnum=13)的医嘱才能恢复
|
||||
let hasStopOrder = false;
|
||||
for (let index = 0; index < selectRows.length; index++) {
|
||||
const item = selectRows[index];
|
||||
if (item.statusEnum == 6) {
|
||||
if (item.statusEnum == 6 || item.statusEnum == 13) {
|
||||
hasStopOrder = true;
|
||||
break;
|
||||
}
|
||||
@@ -2322,7 +2359,7 @@ function handleResumeAdvice() {
|
||||
if (!hasStopOrder) {
|
||||
ElMessage({
|
||||
type: 'error',
|
||||
message: '请选择已停止的医嘱进行恢复',
|
||||
message: '请选择已停止或已停嘱的医嘱进行恢复',
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -2330,7 +2367,7 @@ function handleResumeAdvice() {
|
||||
let allStop = true;
|
||||
for (let index = 0; index < selectRows.length; index++) {
|
||||
const item = selectRows[index];
|
||||
if (item.statusEnum != 6) {
|
||||
if (item.statusEnum != 6 && item.statusEnum != 13) {
|
||||
allStop = false;
|
||||
break;
|
||||
}
|
||||
@@ -2338,7 +2375,7 @@ function handleResumeAdvice() {
|
||||
if (!allStop) {
|
||||
ElMessage({
|
||||
type: 'error',
|
||||
message: '恢复操作只能选择已停止的医嘱,请重新选择',
|
||||
message: '恢复操作只能选择已停止或已停嘱的医嘱,请重新选择',
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -2384,10 +2421,10 @@ function combination() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 找出停嘱的
|
||||
// 找出停嘱的(已停止或已停嘱的不允许组合)
|
||||
for (let index = 0; index < selectRows.length; index++) {
|
||||
const item = selectRows[index];
|
||||
if (item.statusEnum == 6) {
|
||||
if (item.statusEnum == RequestStatus.STOPPED || item.statusEnum == RequestStatus.PENDING_STOP) {
|
||||
isStop = false;
|
||||
break;
|
||||
}
|
||||
@@ -2484,10 +2521,10 @@ function split() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 找出停嘱的
|
||||
// 找出停嘱的(已停止或已停嘱的不允许拆组)
|
||||
for (let index = 0; index < selectRows.length; index++) {
|
||||
const item = selectRows[index];
|
||||
if (item.statusEnum == 6) {
|
||||
if (item.statusEnum == RequestStatus.STOPPED || item.statusEnum == RequestStatus.PENDING_STOP) {
|
||||
isStop = false;
|
||||
break;
|
||||
}
|
||||
@@ -2782,7 +2819,7 @@ function sortPrescriptionList() {
|
||||
}
|
||||
|
||||
function handleLeaveHospital() {
|
||||
if (!patientInfo.value) {
|
||||
if (!localPatientInfoRef.value) {
|
||||
proxy.$modal.msgWarning('请先选择患者');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<div style="height: calc(100vh - 176px)">
|
||||
<div
|
||||
v-loading="loading"
|
||||
@@ -272,6 +272,10 @@ const props = defineProps({
|
||||
type: Number,
|
||||
default: undefined,
|
||||
},
|
||||
drugType: {
|
||||
type: String,
|
||||
default: '1',
|
||||
},
|
||||
});
|
||||
|
||||
function handleGetPrescription() {
|
||||
@@ -285,6 +289,7 @@ function handleGetPrescription() {
|
||||
therapyEnum: props.therapyEnum,
|
||||
exeStatus: props.exeStatus,
|
||||
requestStatus: props.requestStatus,
|
||||
tcmFlag: props.drugType === '1' ? 0 : 1,
|
||||
})
|
||||
.then((res) => {
|
||||
// try {
|
||||
@@ -359,8 +364,11 @@ function handleMedicineSummary() {
|
||||
return;
|
||||
}
|
||||
let ids = [];
|
||||
const now = proxy.formatDateStr(new Date(), 'YYYY-MM-DD HH:mm:ss');
|
||||
paramList.forEach((item) => {
|
||||
ids.push(...item.dispenseIds);
|
||||
item.dispenseIds.forEach((d) => {
|
||||
ids.push({ ...d, dispenseTime: now });
|
||||
});
|
||||
});
|
||||
if (ids.length === 0) {
|
||||
proxy.$message.warning('所选药品未关联发放信息');
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<div style="height: calc(100vh - 176px)">
|
||||
<div
|
||||
v-loading="loading"
|
||||
@@ -178,6 +178,10 @@ const props = defineProps({
|
||||
type: Number,
|
||||
default: undefined,
|
||||
},
|
||||
drugType: {
|
||||
type: String,
|
||||
default: '1',
|
||||
},
|
||||
});
|
||||
|
||||
handleGetPrescription();
|
||||
@@ -188,6 +192,7 @@ function handleGetPrescription() {
|
||||
if (props.therapyEnum !== undefined) {
|
||||
params.therapyEnum = props.therapyEnum;
|
||||
}
|
||||
params.tcmFlag = props.drugType === '1' ? 0 : 1;
|
||||
getMedicineSummary(params).then((res) => {
|
||||
medicineSummaryFormList.value = res.data.records;
|
||||
loading.value = false;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<div style="display: flex; justify-content: space-between">
|
||||
<div style="width: 20%; height: 90vh; border-right: solid 2px #e4e7ed">
|
||||
<div
|
||||
@@ -56,25 +56,26 @@
|
||||
<el-radio-group
|
||||
v-model="drugType"
|
||||
class="ml10"
|
||||
@change="handleGetPrescription"
|
||||
>
|
||||
<el-radio-button
|
||||
value="1"
|
||||
/>
|
||||
<el-radio-button
|
||||
value="2"
|
||||
/>
|
||||
<el-radio-button value="1">
|
||||
西药
|
||||
</el-radio-button>
|
||||
<el-radio-button value="2">
|
||||
中药
|
||||
</el-radio-button>
|
||||
</el-radio-group>
|
||||
<el-radio-group
|
||||
v-model="isDetails"
|
||||
class="ml20"
|
||||
@change="handleRadioChange"
|
||||
>
|
||||
<el-radio-button
|
||||
value="1"
|
||||
/>
|
||||
<el-radio-button
|
||||
value="2"
|
||||
/>
|
||||
<el-radio-button value="1">
|
||||
明细
|
||||
</el-radio-button>
|
||||
<el-radio-button value="2">
|
||||
汇总
|
||||
</el-radio-button>
|
||||
</el-radio-group>
|
||||
<span class="descriptions-item-label">截止时间:</span>
|
||||
<el-date-picker
|
||||
@@ -132,11 +133,13 @@
|
||||
:request-status="requestStatus"
|
||||
:deadline="deadline"
|
||||
:therapy-enum="therapyEnum"
|
||||
:drug-type="drugType"
|
||||
/>
|
||||
<SummaryMedicineList
|
||||
v-else
|
||||
ref="summaryMedicineRefs"
|
||||
:therapy-enum="therapyEnum"
|
||||
:drug-type="drugType"
|
||||
/>
|
||||
<!-- <el-tabs v-model="activeName" class="demo-tabs centered-tabs" @tab-change="handleClick">
|
||||
<el-tab-pane
|
||||
@@ -158,7 +161,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {getCurrentInstance, nextTick, ref} from 'vue';
|
||||
import {getCurrentInstance, nextTick, provide, ref} from 'vue';
|
||||
import {useRouter} from 'vue-router';
|
||||
import PatientList from '../components/patientList.vue';
|
||||
import PrescriptionList from './components/prescriptionList.vue';
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
<template>
|
||||
<div style="height: calc(100vh - 126px)">
|
||||
<template>
|
||||
<div style="height: calc(100vh - 126px); display: flex; flex-direction: column; overflow: hidden">
|
||||
<div
|
||||
style="
|
||||
height: 51px;
|
||||
border-bottom: 2px solid #e4e7ed;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
flex-shrink: 0;
|
||||
overflow: hidden;
|
||||
"
|
||||
>
|
||||
<div>
|
||||
<div style="display: flex; align-items: center; gap: 12px; flex-shrink: 1; min-width: 0;">
|
||||
<el-radio-group
|
||||
v-model="type"
|
||||
class="ml20"
|
||||
@change="handleRadioChange"
|
||||
>
|
||||
<el-radio :value="null">
|
||||
<el-radio :value="THERAPY_TYPE_ALL">
|
||||
全部
|
||||
</el-radio>
|
||||
<el-radio :value="1">
|
||||
@@ -25,8 +26,17 @@
|
||||
临时
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
<span style="flex-shrink: 0;">截止时间:</span>
|
||||
<el-date-picker
|
||||
v-model="deadline"
|
||||
type="datetime"
|
||||
format="YYYY-MM-DD HH:mm:ss"
|
||||
placeholder="选择截止时间"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
:clearable="false"
|
||||
style="width: 200px;"
|
||||
/>
|
||||
<el-button
|
||||
class="ml20"
|
||||
type="primary"
|
||||
plain
|
||||
@click="handleGetPrescription"
|
||||
@@ -34,21 +44,20 @@
|
||||
查询
|
||||
</el-button>
|
||||
</div>
|
||||
<div>
|
||||
<span class="descriptions-item-label">全选:</span>
|
||||
<div style="flex: 1; min-width: 0;"></div>
|
||||
<div style="display: flex; align-items: center; gap: 12px; flex-shrink: 1; min-width: 0;">
|
||||
<span class="descriptions-item-label" style="flex-shrink: 0;">全选:</span>
|
||||
<el-switch
|
||||
v-model="chooseAll"
|
||||
@change="handelSwitchChange"
|
||||
/>
|
||||
<el-button
|
||||
class="ml20"
|
||||
type="primary"
|
||||
@click="handleCheck"
|
||||
>
|
||||
核对通过
|
||||
</el-button>
|
||||
<el-button
|
||||
class="ml20 mr20"
|
||||
type="danger"
|
||||
:disabled="hasDispensedSelected"
|
||||
@click="handleCancel"
|
||||
@@ -59,7 +68,7 @@
|
||||
</div>
|
||||
<div
|
||||
v-loading="loading"
|
||||
style="padding: 10px; background-color: #eef9fd; height: 100%; overflow-y: auto"
|
||||
style="padding: 10px; background-color: #eef9fd; flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden"
|
||||
>
|
||||
<el-collapse
|
||||
v-if="prescriptionList.length > 0"
|
||||
@@ -69,8 +78,6 @@
|
||||
border-bottom: 0px;
|
||||
border-top: 0px;
|
||||
border-radius: 0px;
|
||||
overflow-y: auto;
|
||||
max-height: calc(100vh - 200px);
|
||||
"
|
||||
>
|
||||
<el-collapse-item
|
||||
@@ -81,12 +88,11 @@
|
||||
border: 2px solid #e4e7ed;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 10px;
|
||||
overflow: hidden;
|
||||
"
|
||||
>
|
||||
<template #title>
|
||||
<div style="display: flex; justify-content: space-between; align-items: center">
|
||||
<div>
|
||||
<div style="display: flex; gap: 16px; align-items: center; width: 100%; min-width: 0; overflow: hidden">
|
||||
<div style="flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; padding-right: 12px;">
|
||||
<span>{{ item[0].bedName + '【' + item[0].busNo + '】' }}</span>
|
||||
<span>
|
||||
{{
|
||||
@@ -103,17 +109,18 @@
|
||||
<div
|
||||
style="
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 20px;
|
||||
align-items: center;
|
||||
margin-right: 20px;
|
||||
flex-shrink: 1;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
"
|
||||
>
|
||||
<div style="display: inline-block; margin-right: 10px">
|
||||
<div style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0;">
|
||||
<span class="descriptions-item-label">住院医生:</span>
|
||||
<span>{{ item[0].requesterId_dictText }}</span>
|
||||
</div>
|
||||
<div style="display: inline-block; margin-right: 10px">
|
||||
<div style="white-space: nowrap; flex-shrink: 0;">
|
||||
<div
|
||||
class="descriptions-item-label"
|
||||
style="height: 20px; line-height: 20px; text-align: center; margin: 0"
|
||||
@@ -135,6 +142,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div style="overflow-x: auto">
|
||||
<vxe-table
|
||||
:ref="'tableRef' + index"
|
||||
:data="item"
|
||||
@@ -168,6 +176,7 @@
|
||||
<vxe-column
|
||||
title="医嘱内容"
|
||||
field="adviceName"
|
||||
min-width="220"
|
||||
>
|
||||
<template #default="scope">
|
||||
<span>
|
||||
@@ -217,7 +226,88 @@
|
||||
field="requestTime"
|
||||
width="230"
|
||||
/>
|
||||
<vxe-column
|
||||
title="开始时间"
|
||||
field="startTime"
|
||||
width="150"
|
||||
align="center"
|
||||
/>
|
||||
<vxe-column
|
||||
title="单次剂量"
|
||||
field="singleDose"
|
||||
width="100"
|
||||
align="center"
|
||||
/>
|
||||
<vxe-column
|
||||
title="总量"
|
||||
field="totalAmount"
|
||||
width="100"
|
||||
align="center"
|
||||
/>
|
||||
<vxe-column
|
||||
title="频次/用法"
|
||||
field="frequencyUsage"
|
||||
width="110"
|
||||
align="center"
|
||||
/>
|
||||
<vxe-column
|
||||
title="皮试"
|
||||
field="skinTestStatus"
|
||||
width="90"
|
||||
align="center"
|
||||
>
|
||||
<template #default="scope">
|
||||
<el-tag
|
||||
v-if="scope.row.skinTestStatus"
|
||||
:type="scope.row.skinTestHighlight ? 'danger' : 'info'"
|
||||
:class="{ 'skin-test-warning': scope.row.skinTestHighlight }"
|
||||
size="small"
|
||||
>
|
||||
{{ scope.row.skinTestStatus }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column
|
||||
title="注射药品"
|
||||
field="isInjection"
|
||||
width="90"
|
||||
align="center"
|
||||
>
|
||||
<template #default="scope">
|
||||
<el-tag
|
||||
v-if="scope.row.isInjection"
|
||||
type="warning"
|
||||
size="small"
|
||||
>
|
||||
注射
|
||||
</el-tag>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column
|
||||
title="开嘱医生"
|
||||
field="orderingDoctor"
|
||||
width="100"
|
||||
align="center"
|
||||
/>
|
||||
<vxe-column
|
||||
title="诊断"
|
||||
field="diagnosis"
|
||||
min-width="150"
|
||||
/>
|
||||
<vxe-column
|
||||
title="停嘱时间"
|
||||
field="stopTime"
|
||||
width="150"
|
||||
align="center"
|
||||
/>
|
||||
<vxe-column
|
||||
title="停嘱医生"
|
||||
field="stopperName"
|
||||
width="100"
|
||||
align="center"
|
||||
/>
|
||||
</vxe-table>
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
<el-empty
|
||||
@@ -256,7 +346,8 @@ import {RequestStatus} from '@/utils/medicalConstants';
|
||||
const activeNames = ref([]);
|
||||
const prescriptionList = ref([]);
|
||||
const deadline = ref(formatDateStr(new Date(), 'YYYY-MM-DD') + ' 23:59:59');
|
||||
const type = ref(null);
|
||||
const THERAPY_TYPE_ALL = 0;
|
||||
const type = ref(THERAPY_TYPE_ALL);
|
||||
const backReasonVisible = ref(false);
|
||||
const backReasonForm = ref({ reason: '' });
|
||||
const backReasonFormRef = ref(null);
|
||||
@@ -311,13 +402,14 @@ const getStatusDisplayText = (row) => {
|
||||
|
||||
const getStatusType = (status) => {
|
||||
const map = {
|
||||
1: 'info',
|
||||
2: 'primary',
|
||||
3: 'success',
|
||||
4: 'warning',
|
||||
5: 'danger',
|
||||
6: 'danger',
|
||||
7: 'info',
|
||||
[RequestStatus.DRAFT]: 'info',
|
||||
[RequestStatus.ACTIVE]: 'primary',
|
||||
[RequestStatus.COMPLETED]: 'success',
|
||||
[RequestStatus.ON_HOLD]: 'warning',
|
||||
[RequestStatus.CANCELLED]: 'danger',
|
||||
[RequestStatus.PENDING_STOP]: 'warning',
|
||||
[RequestStatus.STOPPED]: 'danger',
|
||||
[RequestStatus.ENDED]: 'info',
|
||||
};
|
||||
return map[status] || 'info';
|
||||
};
|
||||
@@ -355,7 +447,8 @@ function handleGetPrescription() {
|
||||
getPrescriptionList({
|
||||
encounterIds: encounterIds,
|
||||
requestStatus: props.requestStatus,
|
||||
...(type.value != null ? { therapyEnum: type.value } : {}),
|
||||
...(type.value !== THERAPY_TYPE_ALL ? { therapyEnum: type.value } : {}),
|
||||
deadline: deadline.value,
|
||||
pageSize: 10000,
|
||||
pageNo: 1,
|
||||
}).then((res) => {
|
||||
@@ -375,8 +468,6 @@ function handleGetPrescription() {
|
||||
|
||||
// 将分组结果转换为数组形式
|
||||
prescriptionList.value = Object.values(groupedPrescriptions);
|
||||
console.log(prescriptionList.value, '1111');
|
||||
console.log('@@@@@=======>', JSON.stringify(prescriptionList.value));
|
||||
loading.value = false;
|
||||
getGroupMarkers();
|
||||
});
|
||||
@@ -394,7 +485,6 @@ function getGroupMarkers() {
|
||||
prescription.groupIcon = null;
|
||||
});
|
||||
});
|
||||
console.log('prescriptionList====>', JSON.stringify(prescriptionList.value));
|
||||
// 创建一个映射来存储每个 groupId 对应的行索引
|
||||
const groupMap = {};
|
||||
|
||||
@@ -432,7 +522,6 @@ function getGroupMarkers() {
|
||||
});
|
||||
}
|
||||
});
|
||||
console.log('prescriptionList====>', JSON.stringify(prescriptionList.value));
|
||||
}
|
||||
|
||||
// 选择框改变时的处理
|
||||
@@ -452,7 +541,6 @@ function handleCheck() {
|
||||
handleGetPrescription();
|
||||
}
|
||||
});
|
||||
console.log(list, 'list');
|
||||
} else {
|
||||
proxy.$message.warning('请先选择医嘱信息');
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div style="display: flex; justify-content: space-between">
|
||||
<div style="width: 20%; height: 90vh; border-right: solid 2px #e4e7ed">
|
||||
<div style="display: flex; height: 90vh; overflow: hidden">
|
||||
<div style="width: 20%; flex-shrink: 0; border-right: solid 2px #e4e7ed; overflow: hidden">
|
||||
<div
|
||||
style="
|
||||
height: 40px;
|
||||
@@ -37,7 +37,7 @@
|
||||
-->
|
||||
</el-tabs>
|
||||
</div>
|
||||
<div style="width: 100%">
|
||||
<div style="flex: 1; min-width: 0; overflow: hidden">
|
||||
<el-tabs
|
||||
v-model="activeName"
|
||||
class="centered-tabs"
|
||||
|
||||
@@ -10,5 +10,5 @@ export function addReport(d){return request({url:'/reconstruction/report/add',me
|
||||
export function submitReport(id){return request({url:'/reconstruction/report/submit/'+id,method:'put'})}
|
||||
export function verifyReport(id,doctor){return request({url:'/reconstruction/report/verify/'+id,method:'put',params:{doctor}})}
|
||||
export function getStats(){return request({url:'/reconstruction/stats',method:'get'})}
|
||||
// 获取医生列表(有医生角色的用户)
|
||||
export function getDoctorList(){return request({url:'/system/user/list',method:'get',params:{pageSize:200}})}
|
||||
// Get all active users for doctor selection
|
||||
export function getDoctorList(){return request({url:'/system/user/list',method:'get',params:{status:'0',pageSize:200}})}
|
||||
|
||||
@@ -230,7 +230,9 @@ function init(){
|
||||
|
||||
// Generate volume
|
||||
const volData=genVolume()
|
||||
const volTex=new THREE.DataTexture(volData,SZ,SZ,SZ,THREE.RedFormat,THREE.FloatType)
|
||||
const volTex=new THREE.Data3DTexture(volData,SZ,SZ,SZ)
|
||||
volTex.format=THREE.RedFormat
|
||||
volTex.type=THREE.FloatType
|
||||
volTex.needsUpdate=true
|
||||
volTex.minFilter=THREE.LinearFilter
|
||||
volTex.magFilter=THREE.LinearFilter
|
||||
@@ -321,9 +323,19 @@ watch(mode,(val)=>{
|
||||
})
|
||||
|
||||
onMounted(()=>{
|
||||
nextTick(()=>{
|
||||
setTimeout(init,100)
|
||||
// Use ResizeObserver to init only when container has dimensions
|
||||
const el=containerRef.value
|
||||
if(!el)return
|
||||
const ro=new ResizeObserver(entries=>{
|
||||
for(const e of entries){
|
||||
if(e.contentRect.width>0&&e.contentRect.height>0&&!renderer){
|
||||
init()
|
||||
ro.disconnect()
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
ro.observe(el)
|
||||
window.addEventListener('resize',onResize)
|
||||
})
|
||||
|
||||
@@ -336,9 +348,9 @@ onUnmounted(()=>{
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.viewer-wrap{display:flex;flex-direction:column;height:100%;background:#0a0a1a;color:#fff}
|
||||
.viewer-wrap{display:flex;flex-direction:column;min-height:600px;height:100%;background:#0a0a1a;color:#fff}
|
||||
.vbar{display:flex;gap:8px;padding:8px 12px;background:#1a1a2e;border-bottom:1px solid #333;align-items:center;flex-wrap:wrap}
|
||||
.vmain{flex:1;position:relative;overflow:hidden;background:#0a0a1a}
|
||||
.vmain{flex:1;position:relative;overflow:hidden;background:#0a0a1a;min-height:500px}
|
||||
.gl-canvas{width:100%;height:100%;display:block}
|
||||
.ov-tl{position:absolute;top:8px;left:8px;padding:6px 10px;background:rgba(0,0,0,.7);border-radius:4px;font-size:11px;font-family:'Courier New',monospace;color:#0f0;line-height:1.5;pointer-events:none;z-index:10}
|
||||
.ov-bl{position:absolute;bottom:8px;left:8px;padding:6px 10px;background:rgba(0,0,0,.7);border-radius:4px;font-size:11px;font-family:'Courier New',monospace;color:#0f0;pointer-events:none;z-index:10}
|
||||
|
||||
8
node_modules/.vite/deps/_metadata.json
generated
vendored
8
node_modules/.vite/deps/_metadata.json
generated
vendored
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"hash": "5905b5e1",
|
||||
"configHash": "4d078017",
|
||||
"lockfileHash": "9e11ee45",
|
||||
"browserHash": "09dcaa6f",
|
||||
"optimized": {},
|
||||
"chunks": {}
|
||||
}
|
||||
3
node_modules/.vite/deps/package.json
generated
vendored
3
node_modules/.vite/deps/package.json
generated
vendored
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"type": "module"
|
||||
}
|
||||
Reference in New Issue
Block a user