Compare commits
1 Commits
develop
...
fix/BUG#61
| Author | SHA1 | Date | |
|---|---|---|---|
| e8d10befbd |
@@ -1920,7 +1920,7 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
|
||||
Surgery surgery = iSurgeryService.getOne(
|
||||
new LambdaQueryWrapper<Surgery>()
|
||||
.eq(Surgery::getSurgeryNo, prescriptionNo)
|
||||
.and(w -> w.isNull(Surgery::getDeleteFlag).or().eq(Surgery::getDeleteFlag, "0")).last("LIMIT 1"));
|
||||
.and(w -> w.isNull(Surgery::getDeleteFlag).or().eq(Surgery::getDeleteFlag, "0")));
|
||||
if (surgery != null) {
|
||||
iSurgeryService.removeById(surgery.getId());
|
||||
log.info("handService - 级联删除手术记录 cli_surgery: surgeryNo={}, id={}", prescriptionNo, surgery.getId());
|
||||
@@ -2186,7 +2186,7 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
|
||||
.eq(ChargeItem::getServiceId, adviceSaveDto.getRequestId())
|
||||
.eq(ChargeItem::getServiceTable, CommonConstants.TableName.WOR_SERVICE_REQUEST)
|
||||
.eq(ChargeItem::getDeleteFlag, DelFlag.NO.getCode())
|
||||
.last("LIMIT 1"));
|
||||
);
|
||||
log.info("BugFix#328: 通过requestId查询费用项,requestId={}, chargeItem={}",
|
||||
adviceSaveDto.getRequestId(), existingChargeItem != null ? existingChargeItem.getId() : "null");
|
||||
}
|
||||
@@ -2295,7 +2295,7 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
|
||||
new LambdaQueryWrapper<InventoryItem>()
|
||||
.eq(InventoryItem::getItemId, dispense.getMedicationId())
|
||||
.eq(InventoryItem::getLotNumber, dispense.getLotNumber())
|
||||
.last("LIMIT 1"));
|
||||
);
|
||||
|
||||
if (inventoryItem != null) {
|
||||
// 计算回滚后的数量(加上已发放的数量)
|
||||
|
||||
@@ -29,6 +29,7 @@ import com.openhis.document.service.IEmrTemplateService;
|
||||
import com.openhis.web.doctorstation.appservice.IDoctorStationEmrAppService;
|
||||
import com.openhis.web.doctorstation.dto.EmrTemplateDto;
|
||||
import com.openhis.web.doctorstation.dto.PatientEmrDto;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@@ -41,6 +42,7 @@ import java.util.stream.Collectors;
|
||||
/**
|
||||
* 医生站-电子病历 应用实现类
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class DoctorStationEmrAppServiceImpl implements IDoctorStationEmrAppService {
|
||||
|
||||
@@ -60,13 +62,7 @@ public class DoctorStationEmrAppServiceImpl implements IDoctorStationEmrAppServi
|
||||
IDocRecordService docRecordService;
|
||||
|
||||
@Resource
|
||||
private EncounterMapper encounterMapper;
|
||||
|
||||
@Resource
|
||||
private PatientMapper patientMapper;
|
||||
|
||||
@Resource
|
||||
private com.openhis.administration.mapper.EncounterParticipantMapper encounterParticipantMapper;
|
||||
private com.openhis.web.doctorstation.mapper.DoctorStationEmrAppMapper doctorStationEmrAppMapper;
|
||||
|
||||
/**
|
||||
* 添加病人病历信息
|
||||
@@ -79,7 +75,7 @@ public class DoctorStationEmrAppServiceImpl implements IDoctorStationEmrAppServi
|
||||
Emr emr = new Emr();
|
||||
BeanUtils.copyProperties(patientEmrDto, emr);
|
||||
String contextStr = patientEmrDto.getContextJson().toString();
|
||||
Emr patientEmr = emrService.getOne(new LambdaQueryWrapper<Emr>().eq(Emr::getEncounterId, emr.getEncounterId()).orderByDesc(Emr::getCreateTime).last("LIMIT 1"), false);
|
||||
Emr patientEmr = emrService.getOne(new LambdaQueryWrapper<Emr>().eq(Emr::getEncounterId, emr.getEncounterId()));
|
||||
boolean saveSuccess;
|
||||
// 如果已经保存病历,再次保存走更新
|
||||
if (patientEmr != null) {
|
||||
@@ -126,10 +122,6 @@ public class DoctorStationEmrAppServiceImpl implements IDoctorStationEmrAppServi
|
||||
*/
|
||||
@Override
|
||||
public R<?> getPatientEmrHistory(PatientEmrDto patientEmrDto, Integer pageNo, Integer pageSize) {
|
||||
// 校验参数
|
||||
if (patientEmrDto.getPatientId() == null) {
|
||||
return R.ok(new Page<>(pageNo, pageSize));
|
||||
}
|
||||
Page<Emr> page = emrService.page(new Page<>(pageNo, pageSize),
|
||||
new LambdaQueryWrapper<Emr>().eq(Emr::getPatientId, patientEmrDto.getPatientId()));
|
||||
return R.ok(page);
|
||||
@@ -144,12 +136,8 @@ public class DoctorStationEmrAppServiceImpl implements IDoctorStationEmrAppServi
|
||||
*/
|
||||
@Override
|
||||
public R<?> getEmrDetail(Long encounterId) {
|
||||
// 校验参数
|
||||
if (encounterId == null) {
|
||||
return R.ok(null);
|
||||
}
|
||||
// 先查询门诊病历(emr表)
|
||||
Emr emrDetail = emrService.getOne(new LambdaQueryWrapper<Emr>().eq(Emr::getEncounterId, encounterId).orderByDesc(Emr::getCreateTime).last("LIMIT 1"), false);
|
||||
Emr emrDetail = emrService.getOne(new LambdaQueryWrapper<Emr>().eq(Emr::getEncounterId, encounterId));
|
||||
if (emrDetail != null) {
|
||||
return R.ok(emrDetail);
|
||||
}
|
||||
@@ -159,8 +147,7 @@ public class DoctorStationEmrAppServiceImpl implements IDoctorStationEmrAppServi
|
||||
new LambdaQueryWrapper<DocRecord>()
|
||||
.eq(DocRecord::getEncounterId, encounterId)
|
||||
.orderByDesc(DocRecord::getCreateTime)
|
||||
.last("LIMIT 1"),
|
||||
false
|
||||
.last("LIMIT 1")
|
||||
);
|
||||
if (docRecord != null) {
|
||||
// 住院病历存在,也返回数据
|
||||
@@ -232,52 +219,29 @@ public class DoctorStationEmrAppServiceImpl implements IDoctorStationEmrAppServi
|
||||
* @return 待写病历列表
|
||||
*/
|
||||
@Override
|
||||
public R<?> getPendingEmrList(Long doctorId) {
|
||||
// 由于Encounter实体中没有jzPractitionerUserId字段,我们需要通过关联查询来获取相关信息
|
||||
// 使用医生工作站的mapper来查询相关数据
|
||||
// 这里我们直接使用医生工作站的查询逻辑
|
||||
public R<?> getPendingEmrList(Long doctorId, Integer pageNo, Integer pageSize, String patientName) {
|
||||
// 先查询总数
|
||||
Long total = doctorStationEmrAppMapper.getPendingEmrCount(doctorId, patientName);
|
||||
|
||||
// 查询当前医生负责的、状态为"就诊中"但还没有写病历的患者
|
||||
// 需要通过EncounterParticipant表来关联医生信息
|
||||
List<Encounter> encounters = encounterMapper.selectList(
|
||||
new LambdaQueryWrapper<Encounter>()
|
||||
.eq(Encounter::getStatusEnum, EncounterStatus.IN_PROGRESS.getValue())
|
||||
);
|
||||
// 计算分页偏移量,再查询分页数据
|
||||
int offset = (pageNo - 1) * pageSize;
|
||||
List<Map<String, Object>> pageRows = doctorStationEmrAppMapper.getPendingEmrList(doctorId, patientName, pageSize, offset);
|
||||
|
||||
// 过滤出由指定医生负责且还没有写病历的就诊记录
|
||||
List<Map<String, Object>> pendingEmrs = new ArrayList<>();
|
||||
for (Encounter encounter : encounters) {
|
||||
// 检查该就诊记录是否已经有病历
|
||||
Emr existingEmr = emrService.getOne(
|
||||
new LambdaQueryWrapper<Emr>().eq(Emr::getEncounterId, encounter.getId()).orderByDesc(Emr::getCreateTime).last("LIMIT 1"), false
|
||||
);
|
||||
|
||||
// 检查该就诊是否由指定医生负责
|
||||
boolean isAssignedToDoctor = isEncounterAssignedToDoctor(encounter.getId(), doctorId);
|
||||
|
||||
if (existingEmr == null && isAssignedToDoctor) {
|
||||
// 如果没有病历且由该医生负责,则添加到待写病历列表
|
||||
Map<String, Object> pendingEmr = new java.util.HashMap<>();
|
||||
|
||||
// 获取患者信息
|
||||
Patient patient = patientMapper.selectById(encounter.getPatientId());
|
||||
|
||||
pendingEmr.put("encounterId", encounter.getId());
|
||||
pendingEmr.put("patientId", encounter.getPatientId());
|
||||
pendingEmr.put("patientName", patient != null ? patient.getName() : "未知");
|
||||
pendingEmr.put("gender", patient != null ? patient.getGenderEnum() : null);
|
||||
// 使用出生日期计算年龄
|
||||
pendingEmr.put("age", patient != null && patient.getBirthDate() != null ?
|
||||
calculateAge(patient.getBirthDate()) : null);
|
||||
// 使用创建时间作为挂号时间
|
||||
pendingEmr.put("registerTime", encounter.getCreateTime());
|
||||
pendingEmr.put("busNo", encounter.getBusNo()); // 病历号
|
||||
|
||||
pendingEmrs.add(pendingEmr);
|
||||
// 计算年龄列
|
||||
for (Map<String, Object> row : pageRows) {
|
||||
Object birthDate = row.get("birthDate");
|
||||
if (birthDate instanceof Date) {
|
||||
row.put("age", calculateAge((Date) birthDate));
|
||||
} else {
|
||||
row.put("age", null);
|
||||
}
|
||||
row.remove("birthDate");
|
||||
}
|
||||
|
||||
return R.ok(pendingEmrs);
|
||||
Map<String, Object> result = new java.util.HashMap<>();
|
||||
result.put("rows", pageRows);
|
||||
result.put("total", total != null ? total : 0L);
|
||||
return R.ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -287,14 +251,9 @@ public class DoctorStationEmrAppServiceImpl implements IDoctorStationEmrAppServi
|
||||
* @return 待写病历数量
|
||||
*/
|
||||
@Override
|
||||
public R<?> getPendingEmrCount(Long doctorId) {
|
||||
// 获取待写病历列表,然后返回数量
|
||||
R<?> result = getPendingEmrList(doctorId);
|
||||
if (result.getCode() == 200) {
|
||||
List<?> pendingEmrs = (List<?>) result.getData();
|
||||
return R.ok(pendingEmrs.size());
|
||||
}
|
||||
return R.ok(0);
|
||||
public R<?> getPendingEmrCount(Long doctorId, String patientName) {
|
||||
Long count = doctorStationEmrAppMapper.getPendingEmrCount(doctorId, patientName);
|
||||
return R.ok(count != null ? count.intValue() : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -307,7 +266,7 @@ public class DoctorStationEmrAppServiceImpl implements IDoctorStationEmrAppServi
|
||||
public R<?> checkNeedWriteEmr(Long encounterId) {
|
||||
// 检查该就诊记录是否已经有病历
|
||||
Emr existingEmr = emrService.getOne(
|
||||
new LambdaQueryWrapper<Emr>().eq(Emr::getEncounterId, encounterId).orderByDesc(Emr::getCreateTime).last("LIMIT 1"), false
|
||||
new LambdaQueryWrapper<Emr>().eq(Emr::getEncounterId, encounterId)
|
||||
);
|
||||
|
||||
// 如果没有病历,则需要写病历
|
||||
@@ -315,24 +274,6 @@ public class DoctorStationEmrAppServiceImpl implements IDoctorStationEmrAppServi
|
||||
return R.ok(needWrite);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查就诊是否分配给指定医生
|
||||
*
|
||||
* @param encounterId 就诊ID
|
||||
* @param doctorId 医生ID
|
||||
* @return 是否分配给指定医生
|
||||
*/
|
||||
private boolean isEncounterAssignedToDoctor(Long encounterId, Long doctorId) {
|
||||
// 查询就诊参与者表,检查是否有指定医生的接诊记录
|
||||
com.openhis.administration.domain.EncounterParticipant participant =
|
||||
encounterParticipantMapper.selectOne(
|
||||
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<com.openhis.administration.domain.EncounterParticipant>()
|
||||
.eq(com.openhis.administration.domain.EncounterParticipant::getEncounterId, encounterId)
|
||||
.eq(com.openhis.administration.domain.EncounterParticipant::getPractitionerId, doctorId)
|
||||
);
|
||||
|
||||
return participant != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据出生日期计算年龄
|
||||
|
||||
@@ -274,7 +274,7 @@ public class DoctorStationLabApplyServiceImpl implements IDoctorStationInspectio
|
||||
new QueryWrapper<Organization>()
|
||||
.eq("bus_no", performDeptCode)
|
||||
.eq("delete_flag", "0")
|
||||
.last("LIMIT 1"));
|
||||
);
|
||||
if (organization != null) {
|
||||
positionId = organization.getId();
|
||||
} else {
|
||||
@@ -410,7 +410,7 @@ public class DoctorStationLabApplyServiceImpl implements IDoctorStationInspectio
|
||||
new QueryWrapper<InspectionLabApply>()
|
||||
.eq("apply_no", applyNo)
|
||||
.eq("delete_flag", DelFlag.NO.getCode())
|
||||
.last("LIMIT 1"));
|
||||
);
|
||||
|
||||
if (mainEntity == null) {
|
||||
return null;
|
||||
@@ -532,7 +532,7 @@ public class DoctorStationLabApplyServiceImpl implements IDoctorStationInspectio
|
||||
// 1. 根据申请单号查询检验申请单信息
|
||||
InspectionLabApply inspectionLabApply = inspectionLabApplyService.getOne(
|
||||
new QueryWrapper<InspectionLabApply>().eq("apply_no", applyNo)
|
||||
.last("LIMIT 1"));
|
||||
);
|
||||
|
||||
if (inspectionLabApply == null) {
|
||||
log.warn("未找到申请单号为 [{}] 的检验申请单", applyNo);
|
||||
|
||||
@@ -215,7 +215,7 @@ public class DoctorStationMainAppServiceImpl implements IDoctorStationMainAppSer
|
||||
// 限定当天日期,避免复诊患者匹配到历史队列记录
|
||||
.eq(TriageQueueItem::getQueueDate, LocalDate.now())
|
||||
.eq(TriageQueueItem::getDeleteFlag, "0")
|
||||
.last("LIMIT 1"));
|
||||
);
|
||||
if (queueItem != null) {
|
||||
// 使用 TriageQueueStatus 枚举替代原有硬编码数字 20,保证状态值一致性
|
||||
queueItem.setStatus(TriageQueueStatus.IN_CLINIC.getValue());
|
||||
@@ -282,7 +282,7 @@ public class DoctorStationMainAppServiceImpl implements IDoctorStationMainAppSer
|
||||
.eq(TriageQueueItem::getEncounterId, encounterId)
|
||||
.eq(TriageQueueItem::getQueueDate, LocalDate.now())
|
||||
.eq(TriageQueueItem::getDeleteFlag, "0")
|
||||
.last("LIMIT 1"));
|
||||
);
|
||||
|
||||
// 当天未找到时回退:不限日期查最近一条(防止跨日就诊队列项遗漏更新)
|
||||
if (queueItem == null) {
|
||||
@@ -292,8 +292,8 @@ public class DoctorStationMainAppServiceImpl implements IDoctorStationMainAppSer
|
||||
.eq(TriageQueueItem::getEncounterId, encounterId)
|
||||
.eq(TriageQueueItem::getDeleteFlag, "0")
|
||||
.orderByDesc(TriageQueueItem::getQueueDate)
|
||||
.last("LIMIT 1"));
|
||||
|
||||
.last("LIMIT 1")
|
||||
);
|
||||
if (queueItem != null) {
|
||||
log.warn("完诊:当天队列项未找到,回退使用最近队列记录 queueDate={}, id={}",
|
||||
queueItem.getQueueDate(), queueItem.getId());
|
||||
|
||||
@@ -582,10 +582,7 @@ public class AdviceProcessAppServiceImpl implements IAdviceProcessAppService {
|
||||
// 处理长期已发放的药品
|
||||
if (!longMedDispensedList.isEmpty()) {
|
||||
// 生成退药单
|
||||
this.creatRefundMedicationList(longMedDispensedList, procedureIdMap);
|
||||
// 药品退药请求状态变更(待退药)
|
||||
medicationRequestService.updateCancelledStatusBatch(
|
||||
longMedDispensedList.stream().map(MedicationDispense::getMedReqId).toList(), null, null);
|
||||
this.creatRefundMedicationList(tempMedDispensedList, procedureIdMap);
|
||||
}
|
||||
// 处理临时已发放药品
|
||||
if (!tempMedDispensedList.isEmpty()) {
|
||||
|
||||
@@ -660,7 +660,7 @@ public class AdviceManageAppServiceImpl implements IAdviceManageAppService {
|
||||
longServiceRequest.setPatientId(regAdviceSaveDto.getPatientId()); // 患者
|
||||
longServiceRequest.setRequesterId(regAdviceSaveDto.getPractitionerId()); // 开方医生
|
||||
longServiceRequest.setEncounterId(regAdviceSaveDto.getEncounterId()); // 就诊id
|
||||
longServiceRequest.setOrgId(regAdviceSaveDto.getEffectiveOrgId()); // 执行科室
|
||||
longServiceRequest.setOrgId(regAdviceSaveDto.getPositionId()); // 执行科室
|
||||
longServiceRequest.setContentJson(regAdviceSaveDto.getContentJson()); // 请求内容json
|
||||
longServiceRequest.setYbClassEnum(regAdviceSaveDto.getYbClassEnum());// 类别医保编码
|
||||
longServiceRequest.setConditionId(regAdviceSaveDto.getConditionId()); // 诊断id
|
||||
@@ -712,7 +712,7 @@ public class AdviceManageAppServiceImpl implements IAdviceManageAppService {
|
||||
tempServiceRequest.setRequesterId(regAdviceSaveDto.getPractitionerId()); // 开方医生
|
||||
tempServiceRequest.setEncounterId(regAdviceSaveDto.getEncounterId()); // 就诊id
|
||||
tempServiceRequest.setAuthoredTime(curDate); // 请求签发时间
|
||||
tempServiceRequest.setOrgId(regAdviceSaveDto.getEffectiveOrgId()); // 执行科室
|
||||
tempServiceRequest.setOrgId(regAdviceSaveDto.getPositionId()); // 执行科室
|
||||
tempServiceRequest.setContentJson(regAdviceSaveDto.getContentJson()); // 请求内容json
|
||||
tempServiceRequest.setYbClassEnum(regAdviceSaveDto.getYbClassEnum());// 类别医保编码
|
||||
tempServiceRequest.setConditionId(regAdviceSaveDto.getConditionId()); // 诊断id
|
||||
|
||||
@@ -10,4 +10,8 @@ import lombok.experimental.Accessors;
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class RegAdviceSaveDto extends AdviceSaveDto {
|
||||
|
||||
/** 请求类型 */
|
||||
private Integer categoryEnum;
|
||||
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ public class MedicationRequest extends HisBaseEntity {
|
||||
private String supportInfo;
|
||||
|
||||
/** 退回原因 */
|
||||
private String backReason = "";
|
||||
private String backReason;
|
||||
|
||||
/** 请求开始时间 */
|
||||
private Date reqAuthoredTime;
|
||||
|
||||
@@ -115,6 +115,7 @@
|
||||
v-model="form.categoryCode"
|
||||
clearable
|
||||
filterable
|
||||
:disabled="form.isEditInfoDisable === 1"
|
||||
no-data-text=""
|
||||
>
|
||||
<el-option
|
||||
@@ -191,6 +192,7 @@
|
||||
clearable
|
||||
filterable
|
||||
style="width: 240px"
|
||||
:disabled="form.isEditInfoDisable === 1 || form.isEditInfoDisable === 2"
|
||||
no-data-text=""
|
||||
>
|
||||
<el-option
|
||||
@@ -256,6 +258,7 @@
|
||||
placeholder=""
|
||||
clearable
|
||||
filterable
|
||||
:disabled="form.isEditInfoDisable === 1"
|
||||
no-data-text=""
|
||||
>
|
||||
<el-option
|
||||
@@ -320,6 +323,7 @@
|
||||
<el-input
|
||||
v-model="form.retailPrice"
|
||||
placeholder=""
|
||||
:disabled="form.isEditInfoDisable === 1"
|
||||
@input="updatePrices"
|
||||
/>
|
||||
</el-form-item>
|
||||
@@ -400,6 +404,7 @@
|
||||
controls-position="right"
|
||||
:min="1"
|
||||
:max="999"
|
||||
:disabled="form.isEditInfoDisable === 1"
|
||||
@change="calculateTotalPrice"
|
||||
/>
|
||||
</el-form-item>
|
||||
@@ -600,6 +605,8 @@ function calculateTotalPrice() {
|
||||
);
|
||||
if (hasValidItem) {
|
||||
form.value.retailPrice = parseFloat(totalPrice.value) || 0;
|
||||
} else {
|
||||
form.value.retailPrice = undefined;
|
||||
}
|
||||
} catch (error) {
|
||||
totalPrice.value = '0.00';
|
||||
|
||||
@@ -375,7 +375,7 @@
|
||||
>
|
||||
<template #default="scope">
|
||||
<span v-if="!scope.row.isEdit">
|
||||
{{ formatUnitText(scope.row) }}
|
||||
{{ scope.row.quantity ? scope.row.quantity + ' ' + scope.row.unitCode_dictText : '' }}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -613,26 +613,6 @@ function getRowDisabled(row) {
|
||||
return row.isEdit;
|
||||
}
|
||||
|
||||
function formatUnitText(row) {
|
||||
if (!row.quantity) return ''
|
||||
const unitText = row.unitCode_dictText
|
||||
// unitCode_dictText 为有效文本时直接使用
|
||||
if (unitText && !/^\d+$/.test(unitText)) return row.quantity + ' ' + unitText
|
||||
// 优先从行级 unitCodeList 查找
|
||||
const list = row.unitCodeList
|
||||
if (list && list.length) {
|
||||
const match = list.find(u => u.value === row.unitCode)
|
||||
if (match) return row.quantity + ' ' + match.label
|
||||
}
|
||||
// 回退:从字典 unit_code 查找
|
||||
if (unit_code.value && unit_code.value.length) {
|
||||
const dictMatch = unit_code.value.find(d => d.value === row.unitCode)
|
||||
if (dictMatch) return row.quantity + ' ' + dictMatch.label
|
||||
}
|
||||
// 最后兜底用 unitCode
|
||||
return row.quantity + ' ' + (row.unitCode || '')
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否已由医生接诊(非待诊)
|
||||
* EncounterStatus: 1=待诊 2=在诊 3=暂离 …
|
||||
|
||||
@@ -211,37 +211,14 @@ const handleRowClick = (row) => {
|
||||
// 写病历
|
||||
const handleWriteEmr = (row) => {
|
||||
console.log('写病历:', row)
|
||||
// 弹出写病历弹窗
|
||||
ElMessageBox.confirm('确定要为患者 ' + row.patientName + ' 写病历吗?', '确认', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'info'
|
||||
}).then(() => {
|
||||
// 这里可以跳转到病历编辑页面或弹出病历编辑弹窗
|
||||
ElMessage.success('正在打开病历编辑页面...')
|
||||
// TODO: 实现写病历的具体逻辑
|
||||
// 例如:router.push({ path: '/doctorstation/emr', query: { encounterId: row.encounterId } })
|
||||
}).catch(() => {
|
||||
// 取消操作
|
||||
})
|
||||
// 这里可以触发写病历事件
|
||||
// 可能需要跳转到病历编辑页面
|
||||
}
|
||||
|
||||
// 查看患者
|
||||
const handleViewPatient = (row) => {
|
||||
console.log('查看患者:', row)
|
||||
// 弹出查看患者弹窗
|
||||
ElMessageBox.confirm('确定要查看患者 ' + row.patientName + ' 的详细信息吗?', '确认', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'info'
|
||||
}).then(() => {
|
||||
// 这里可以跳转到患者详情页面或弹出患者详情弹窗
|
||||
ElMessage.success('正在打开患者详情页面...')
|
||||
// TODO: 实现查看患者的具体逻辑
|
||||
// 例如:router.push({ path: '/doctorstation/patient-details', query: { encounterId: row.encounterId } })
|
||||
}).catch(() => {
|
||||
// 取消操作
|
||||
})
|
||||
// 这里可以触发查看患者事件
|
||||
}
|
||||
|
||||
// 获取性别文本
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
:title="isUpdateMode ? '修改中医诊断' : '添加中医诊断'"
|
||||
v-model="props.openAddDiagnosisDialog"
|
||||
title="添加中医诊断"
|
||||
width="1500px"
|
||||
append-to-body
|
||||
destroy-on-close
|
||||
@@ -51,7 +51,7 @@
|
||||
<div class="search-box">
|
||||
<el-input
|
||||
v-model="searchMiddleDisease"
|
||||
placeholder="搜索证候名称或编码"
|
||||
placeholder="搜索疾病名称或编码"
|
||||
clearable
|
||||
>
|
||||
<template #prefix>
|
||||
@@ -131,7 +131,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { getTcmCondition, getTcmSyndrome, saveTcmDiagnosis, updateTcmDiagnosis, getTcmDiagnosis } from '@/views/doctorstation/components/api';
|
||||
import {getTcmCondition, getTcmSyndrome, saveTcmDiagnosis,} from '@/views/doctorstation/components/api';
|
||||
import {computed} from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
@@ -143,17 +143,13 @@ const props = defineProps({
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
updateZy: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
});
|
||||
|
||||
const conditionList = ref([]);
|
||||
const syndromeList = ref([]);
|
||||
const tcmDiagonsisList = ref([]);
|
||||
const tcmDiagonsisSaveList = ref([]);
|
||||
const syndromeSelected = ref(false);
|
||||
const syndromeSelected = ref(false); // 当前诊断是否选择对应证候
|
||||
const timestamp = ref('');
|
||||
const selectedDisease = ref(false);
|
||||
const searchDisease = ref('');
|
||||
@@ -161,70 +157,35 @@ const searchMiddleDisease = ref('');
|
||||
const { proxy } = getCurrentInstance();
|
||||
const emit = defineEmits(['close']);
|
||||
|
||||
const dialogVisible = computed({
|
||||
get: () => props.openAddDiagnosisDialog,
|
||||
set: (val) => {
|
||||
if (!val) {
|
||||
emit('close');
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const isUpdateMode = computed(() => {
|
||||
return props.updateZy && props.updateZy.length > 0;
|
||||
});
|
||||
|
||||
function handleOpen() {
|
||||
getTcmCondition().then((res) => {
|
||||
conditionList.value = res.data.records;
|
||||
});
|
||||
|
||||
tcmDiagonsisSaveList.value = [];
|
||||
tcmDiagonsisList.value = [];
|
||||
syndromeSelected.value = true;
|
||||
|
||||
if (isUpdateMode.value) {
|
||||
props.updateZy.forEach((item) => {
|
||||
let updateIds = item.updateId ? item.updateId.split('-') : [];
|
||||
let nameParts = item.name ? item.name.split('-') : [item.name || ''];
|
||||
tcmDiagonsisSaveList.value.push({
|
||||
conditionId: updateIds[0] || '',
|
||||
definitionId: item.illnessDefinitionId || item.definitionId || '',
|
||||
ybNo: item.ybNo,
|
||||
syndromeGroupNo: item.syndromeGroupNo,
|
||||
verificationStatusEnum: item.verificationStatusEnum || 4,
|
||||
medTypeCode: item.medTypeCode,
|
||||
});
|
||||
tcmDiagonsisList.value.push({
|
||||
conditionName: nameParts[0] || '',
|
||||
syndromeName: nameParts[1] || '',
|
||||
syndromeGroupNo: item.syndromeGroupNo,
|
||||
illnessDefinitionId: item.illnessDefinitionId,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索诊断
|
||||
const conditionDatas = computed(() => {
|
||||
if (!searchDisease.value) {
|
||||
return conditionList.value;
|
||||
}
|
||||
return conditionList.value.filter((item) => {
|
||||
return item.name.includes(searchDisease.value) || item.ybNo.includes(searchDisease.value);
|
||||
});
|
||||
});
|
||||
|
||||
const syndromeListDatas = computed(() => {
|
||||
if (!searchMiddleDisease.value) {
|
||||
return syndromeList.value;
|
||||
if (searchDisease.value) {
|
||||
return searchDisease.value == item.name || searchDisease.value == item.ybNo;
|
||||
}
|
||||
return syndromeList.value.filter((item) => {
|
||||
return item.name.includes(searchMiddleDisease.value) || item.ybNo.includes(searchMiddleDisease.value);
|
||||
return conditionList;
|
||||
});
|
||||
});
|
||||
|
||||
// 后证
|
||||
const syndromeListDatas = computed(() => {
|
||||
return syndromeList.value.filter((item) => {
|
||||
if (searchMiddleDisease.value) {
|
||||
return searchMiddleDisease.value == item.name || searchMiddleDisease.value == item.ybNo;
|
||||
}
|
||||
return syndromeList;
|
||||
});
|
||||
});
|
||||
|
||||
// 点击诊断列表处理,点击以后才显示证候列表
|
||||
function handleClickRow(row) {
|
||||
if (syndromeSelected.value || tcmDiagonsisList.value.length === 0) {
|
||||
if (syndromeSelected.value || tcmDiagonsisList.value == 0) {
|
||||
selectedDisease.value = true;
|
||||
syndromeSelected.value = false;
|
||||
timestamp.value = Date.now();
|
||||
@@ -236,7 +197,7 @@ function handleClickRow(row) {
|
||||
ybNo: row.ybNo,
|
||||
syndromeGroupNo: timestamp.value,
|
||||
verificationStatusEnum: 4,
|
||||
medTypeCode: undefined,
|
||||
medTypeCode: undefined, // 不设默认值
|
||||
});
|
||||
tcmDiagonsisList.value.push({
|
||||
conditionName: row.name,
|
||||
@@ -255,6 +216,7 @@ function clickSyndromeRow(row) {
|
||||
syndromeSelected.value = true;
|
||||
}
|
||||
|
||||
// 删除诊断
|
||||
function removeDiagnosis(row, index) {
|
||||
tcmDiagonsisList.value.splice(index, 1);
|
||||
tcmDiagonsisSaveList.value = tcmDiagonsisSaveList.value.filter((item) => {
|
||||
@@ -263,33 +225,6 @@ function removeDiagnosis(row, index) {
|
||||
}
|
||||
|
||||
function save() {
|
||||
const newDiagnosisList = tcmDiagonsisSaveList.value.filter((item) => !item.conditionId);
|
||||
|
||||
if (isUpdateMode.value) {
|
||||
updateTcmDiagnosis({
|
||||
patientId: props.patientInfo.patientId,
|
||||
encounterId: props.patientInfo.encounterId,
|
||||
diagnosisChildList: tcmDiagonsisSaveList.value,
|
||||
}).then((res) => {
|
||||
if (res.code == 200) {
|
||||
if (newDiagnosisList.length > 0) {
|
||||
saveTcmDiagnosis({
|
||||
patientId: props.patientInfo.patientId,
|
||||
encounterId: props.patientInfo.encounterId,
|
||||
diagnosisChildList: newDiagnosisList,
|
||||
}).then((res2) => {
|
||||
if (res2.code == 200) {
|
||||
emit('close');
|
||||
proxy.$modal.msgSuccess('诊断已保存');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
emit('close');
|
||||
proxy.$modal.msgSuccess('诊断已保存');
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
saveTcmDiagnosis({
|
||||
patientId: props.patientInfo.patientId,
|
||||
encounterId: props.patientInfo.encounterId,
|
||||
@@ -301,29 +236,66 @@ function save() {
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function submit() {
|
||||
const hasNewDiagnosis = tcmDiagonsisSaveList.value.some((item) => !item.conditionId);
|
||||
|
||||
if (!hasNewDiagnosis && isUpdateMode.value) {
|
||||
emit('close');
|
||||
return;
|
||||
}
|
||||
|
||||
if (syndromeSelected.value || tcmDiagonsisSaveList.value.length % 2 === 0) {
|
||||
if (tcmDiagonsisSaveList.value.length > 0 && syndromeSelected.value) {
|
||||
save();
|
||||
} else {
|
||||
proxy.$modal.msgWarning('请选择证候');
|
||||
}
|
||||
}
|
||||
|
||||
function close() {
|
||||
emit('close');
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
:deep(.pagination-container .el-pagination) {
|
||||
right: 20px !important;
|
||||
}
|
||||
|
||||
.app-container {
|
||||
max-width: 1400px;
|
||||
margin: 20px auto;
|
||||
padding: 20px;
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 20px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-bottom: 15px;
|
||||
border-bottom: 1px solid var(--el-border-color);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
color: var(--el-color-primary);
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.patient-info {
|
||||
background: var(--el-color-primary-light-9);
|
||||
padding: 15px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.patient-info .info-row {
|
||||
display: flex;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.patient-info .info-label {
|
||||
width: 100px;
|
||||
color: var(--el-text-color-secondary);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1.2fr;
|
||||
@@ -350,13 +322,125 @@ function close() {
|
||||
border-bottom: 1px solid var(--el-border-color);
|
||||
}
|
||||
|
||||
.disease-list {
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.disease-item {
|
||||
padding: 12px 15px;
|
||||
border-bottom: 1px solid var(--el-border-color-lighter);
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.disease-item:hover {
|
||||
background-color: var(--el-color-primary-light-9);
|
||||
}
|
||||
|
||||
.disease-item.active {
|
||||
background-color: var(--el-color-primary-light-8);
|
||||
border-left: 3px solid var(--el-color-primary);
|
||||
}
|
||||
|
||||
.disease-name {
|
||||
font-weight: 500;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.disease-code {
|
||||
font-size: 12px;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
|
||||
.search-box {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.diagnosis-list {
|
||||
max-height: 520px;
|
||||
overflow-y: auto;
|
||||
.disease-categories {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.category-tag {
|
||||
cursor: pointer;
|
||||
padding: 5px 12px;
|
||||
border-radius: 15px;
|
||||
background: var(--el-fill-color-light);
|
||||
font-size: 13px;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.category-tag.active {
|
||||
background: var(--el-color-primary);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.relation-container {
|
||||
text-align: center;
|
||||
padding: 30px 0;
|
||||
border: 2px dashed var(--el-border-color);
|
||||
border-radius: 8px;
|
||||
margin: 20px 0;
|
||||
background: var(--el-fill-color-lighter);
|
||||
}
|
||||
|
||||
.relation-icon {
|
||||
margin-bottom: 15px;
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
.relation-text {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
|
||||
.syndrome-details {
|
||||
padding: 15px;
|
||||
background: var(--el-color-primary-light-9);
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--el-color-primary-light-5);
|
||||
}
|
||||
|
||||
.detail-item {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.detail-label {
|
||||
font-weight: 500;
|
||||
color: var(--el-text-color-secondary);
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 15px;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid var(--el-border-color);
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
padding: 40px 0;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
|
||||
.diagnosis-history {
|
||||
margin-top: 20px;
|
||||
border-top: 1px solid var(--el-border-color);
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
.history-title {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
margin-bottom: 12px;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
|
||||
.history-item {
|
||||
@@ -367,6 +451,17 @@ function close() {
|
||||
border-radius: 0 4px 4px 0;
|
||||
}
|
||||
|
||||
.diagnosis-list {
|
||||
max-height: 520px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.history-date {
|
||||
font-size: 12px;
|
||||
color: var(--el-text-color-secondary);
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.history-diagnosis {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
@@ -374,9 +469,16 @@ function close() {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
padding: 40px 0;
|
||||
.history-note {
|
||||
font-size: 13px;
|
||||
color: var(--el-text-color-secondary);
|
||||
padding-top: 5px;
|
||||
border-top: 1px dashed var(--el-border-color);
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.empty-list {
|
||||
padding: 20px 0;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,60 +1,14 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="visible"
|
||||
title="中医诊断"
|
||||
top="6vh"
|
||||
:width="width"
|
||||
title="中医诊断"
|
||||
:z-index="20"
|
||||
append-to-body
|
||||
destroy-on-close
|
||||
@open="openAct"
|
||||
@closed="closedAct"
|
||||
>
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="rules"
|
||||
label-width="100px"
|
||||
>
|
||||
<el-form-item
|
||||
label="中医诊断"
|
||||
prop="conditionCode"
|
||||
>
|
||||
<el-select
|
||||
v-model="formData.conditionCode"
|
||||
placeholder="请选择中医诊断"
|
||||
filterable
|
||||
clearable
|
||||
style="width: 100%"
|
||||
@change="handleConditionChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in conditionOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label="中医证候"
|
||||
prop="syndromeCode"
|
||||
>
|
||||
<el-select
|
||||
v-model="formData.syndromeCode"
|
||||
placeholder="请选择中医证候"
|
||||
filterable
|
||||
clearable
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in syndromeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
中医诊断
|
||||
<template #footer>
|
||||
<el-button
|
||||
size="fixed"
|
||||
@@ -66,7 +20,7 @@
|
||||
<el-button
|
||||
size="fixed"
|
||||
type="primary"
|
||||
@click="handleSubmit"
|
||||
@click="handleSubmit(signFormRef)"
|
||||
>
|
||||
保存
|
||||
</el-button>
|
||||
@@ -75,111 +29,113 @@
|
||||
</template>
|
||||
<script setup>
|
||||
import {onMounted, reactive, ref} from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { getTcmCondition, getTcmSyndrome, saveTcmDiagnosis } from '../api'
|
||||
import {dayjs} from 'element-plus'
|
||||
// import { IInPatient } from '@/model/IInPatient'
|
||||
|
||||
const { proxy } = getCurrentInstance()
|
||||
const currentInPatient = ref({})
|
||||
const initCurrentInPatient = () => {
|
||||
currentInPatient.value = {
|
||||
feeType: '08',
|
||||
sexName: '男',
|
||||
age: '0',
|
||||
}
|
||||
}
|
||||
/* 初始化数据 */
|
||||
const init = () => {
|
||||
initCurrentInPatient()
|
||||
}
|
||||
|
||||
const conditionOptions = ref([])
|
||||
const syndromeOptions = ref([])
|
||||
|
||||
const formData = ref({
|
||||
conditionCode: '',
|
||||
syndromeCode: '',
|
||||
/* 入科 */
|
||||
const signForm = ref({
|
||||
visitCode: '', // 就诊流水号
|
||||
height: 0, // 身高
|
||||
weight: 0, // 体重
|
||||
temperature: 0, // 体温
|
||||
hertRate: 0, // 心率
|
||||
pulse: 0, // 脉搏
|
||||
highBloodPressure: 0, // 收缩压
|
||||
endBloodPressure: 0, // 舒张压
|
||||
loginDeptCode: '', // 当前登录科室
|
||||
bingqing: '', //患者病情
|
||||
inDeptDate: dayjs(new Date()).format('YYYY-MM-DD HH:mm:ss'), //入院时间
|
||||
signsId: '',
|
||||
})
|
||||
|
||||
const rules = reactive({
|
||||
conditionCode: [{ required: true, message: '请选择中医诊断', trigger: ['blur', 'change'] }],
|
||||
syndromeCode: [{ required: true, message: '请选择中医证候', trigger: ['blur', 'change'] }],
|
||||
admittedDoctor: [{ required: true, message: '请选择住院医生', trigger: ['blur', 'change'] }],
|
||||
masterNurse: [{ required: true, message: '请选择责任护士', trigger: ['blur', 'change'] }],
|
||||
})
|
||||
const printWristband = ref(false)
|
||||
const emits = defineEmits(['okAct'])
|
||||
|
||||
const props = defineProps({
|
||||
patientInfo: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
})
|
||||
|
||||
const emit = defineEmits(['ok-act'])
|
||||
|
||||
const visible = defineModel<boolean>('visible')
|
||||
const width = '500px'
|
||||
const visible = defineModel('visible')
|
||||
const width = '920px'
|
||||
|
||||
/* 取消 */
|
||||
const cancelAct = () => {
|
||||
visible.value = false
|
||||
}
|
||||
|
||||
function handleConditionChange() {
|
||||
formData.value.syndromeCode = ''
|
||||
loadSyndromeOptions(formData.value.conditionCode)
|
||||
}
|
||||
|
||||
function loadConditionOptions() {
|
||||
getTcmCondition().then((res) => {
|
||||
if (res.data && res.data.records) {
|
||||
conditionOptions.value = res.data.records.map((item) => ({
|
||||
value: item.ybNo,
|
||||
label: item.name,
|
||||
}))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function loadSyndromeOptions(conditionCode) {
|
||||
const params = conditionCode ? { conditionCode } : {}
|
||||
getTcmSyndrome(params).then((res) => {
|
||||
if (res.data && res.data.records) {
|
||||
syndromeOptions.value = res.data.records.map((item) => ({
|
||||
value: item.ybNo,
|
||||
label: item.name,
|
||||
}))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const formRef = ref()
|
||||
const handleSubmit = async () => {
|
||||
if (!formRef.value) return
|
||||
await formRef.value.validate((valid) => {
|
||||
/* 录入患者体征*/
|
||||
const signFormRef = ref()
|
||||
const handleSubmit = async (formEl) => {
|
||||
if (!formEl) return
|
||||
await formEl.validate((valid, fields) => {
|
||||
if (valid) {
|
||||
const submitData = {
|
||||
conditionCode: formData.value.conditionCode,
|
||||
syndromeCode: formData.value.syndromeCode,
|
||||
console.log('submit!')
|
||||
try {
|
||||
// 录入患者体征方法(signForm.value).then((res: any) => {
|
||||
// ElMessage({
|
||||
// message: '登记成功!',
|
||||
// type: 'success',
|
||||
// grouping: true,
|
||||
// showClose: true,
|
||||
// })
|
||||
// emits('okAct')
|
||||
// })
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
if (props.patientInfo && props.patientInfo.patientId) {
|
||||
submitData.patientId = props.patientInfo.patientId
|
||||
submitData.encounterId = props.patientInfo.encounterId
|
||||
}
|
||||
submitData.diagnosisChildList = [{
|
||||
conditionCode: formData.value.conditionCode,
|
||||
syndromeCode: formData.value.syndromeCode,
|
||||
}]
|
||||
saveTcmDiagnosis(submitData).then((res) => {
|
||||
if (res.code === 200) {
|
||||
ElMessage.success('中医诊断保存成功')
|
||||
emit('ok-act')
|
||||
cancelAct()
|
||||
} else {
|
||||
ElMessage.error(res.msg || '保存失败')
|
||||
}
|
||||
}).catch(() => {
|
||||
ElMessage.error('保存失败,请重试')
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const openAct = () => {
|
||||
formData.value = { conditionCode: '', syndromeCode: '' }
|
||||
loadConditionOptions()
|
||||
loadSyndromeOptions()
|
||||
init()
|
||||
}
|
||||
const closedAct = () => {
|
||||
visible.value = false
|
||||
}
|
||||
onMounted(() => {
|
||||
loadConditionOptions()
|
||||
})
|
||||
onMounted(() => {})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.transferIn-container {
|
||||
width: 100%;
|
||||
|
||||
.admission-signs,
|
||||
.admission-information {
|
||||
width: 888px;
|
||||
.unit {
|
||||
display: inline-block;
|
||||
margin-left: 10px;
|
||||
color: #bbb;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
font-family: '思源黑体 CN';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.print-wriBtn {
|
||||
margin-left: 565px;
|
||||
}
|
||||
|
||||
.w-p100 {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.w-80 {
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.mb-90 {
|
||||
margin-bottom: 90px !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -159,7 +159,7 @@
|
||||
style="width: 150px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in diag_type"
|
||||
v-for="item in med_type"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
@@ -281,7 +281,6 @@
|
||||
<AddDiagnosisDialog
|
||||
:open-add-diagnosis-dialog="openAddDiagnosisDialog"
|
||||
:patient-info="props.patientInfo"
|
||||
:update-zy="tcmDiagnosisListForEdit"
|
||||
@close="closeDiagnosisDialog"
|
||||
/>
|
||||
</div>
|
||||
@@ -332,15 +331,13 @@ const props = defineProps({
|
||||
const emits = defineEmits(['diagnosisSave']);
|
||||
const { proxy } = getCurrentInstance();
|
||||
const userStore = useUserStore();
|
||||
// 获取诊断类型字典(住院诊断类别)
|
||||
const { diag_type } = proxy.useDict('diag_type');
|
||||
const { med_type } = proxy.useDict('med_type');
|
||||
const rules = ref({
|
||||
name: [{ required: true, message: '请选择诊断', trigger: 'change' }],
|
||||
medTypeCode: [{ required: true, message: '请选择诊断类型', trigger: 'change' }],
|
||||
diagSrtNo: [{ required: true, message: '请输入诊断序号', trigger: 'change' }],
|
||||
});
|
||||
const diagnosisNetDatas = ref([]);
|
||||
const tcmDiagnosisListForEdit = ref([]);
|
||||
|
||||
watch(
|
||||
() => form.value.diagnosisList,
|
||||
@@ -615,13 +612,6 @@ function addDiagnosisItem() {
|
||||
|
||||
// 添加中医诊断
|
||||
function handleAddTcmDiagonsis() {
|
||||
tcmDiagnosisListForEdit.value = form.value.diagnosisList.filter(
|
||||
(item) => item.diagnosisSystem === '中医'
|
||||
).map((item) => ({
|
||||
...item,
|
||||
updateId: item.conditionId ? `${item.conditionId}-${item.syndromeGroupNo || ''}` : '' ,
|
||||
illnessDefinitionId: item.definitionId || '' ,
|
||||
}));
|
||||
openAddDiagnosisDialog.value = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="diagnose-container">
|
||||
<!-- 常用诊断、个人诊断、科室诊断、历史诊断 -->
|
||||
<!-- 常用诊断、个人诊断、科室诊断、历史诊断、 -->
|
||||
<diagnose-folder
|
||||
:folder="mockData"
|
||||
:level="0"
|
||||
@@ -10,44 +10,29 @@
|
||||
<el-space>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="addNewDiagnosis"
|
||||
@click="addNewWestern"
|
||||
>
|
||||
新增诊断
|
||||
开立诊断
|
||||
</el-button>
|
||||
<el-button type="primary">
|
||||
既往诊断
|
||||
</el-button>
|
||||
<!-- 患者诊断 -->
|
||||
<el-button
|
||||
type="primary"
|
||||
type="danger"
|
||||
@click="addNewChinese"
|
||||
>
|
||||
中医诊断
|
||||
</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
:disabled="!selectedRows.length"
|
||||
@click="handleDelete"
|
||||
>
|
||||
删除诊断
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
:loading="saveLoading"
|
||||
@click="handleSaveDiagnosis"
|
||||
>
|
||||
保存诊断
|
||||
</el-button>
|
||||
</el-space>
|
||||
</div>
|
||||
<div class="diagnoseData-container">
|
||||
<el-table
|
||||
ref="diagnoseTableRef"
|
||||
:data="diagnoseData"
|
||||
border
|
||||
row-key="id"
|
||||
style="width: 100%; height: 100%"
|
||||
highlight-current-row
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column
|
||||
type="selection"
|
||||
@@ -55,531 +40,166 @@
|
||||
width="40"
|
||||
/>
|
||||
<el-table-column
|
||||
label="序号"
|
||||
type="index"
|
||||
width="50"
|
||||
fixed="left"
|
||||
prop="date"
|
||||
label="诊断类型"
|
||||
width="180"
|
||||
sortable
|
||||
/>
|
||||
<el-table-column
|
||||
label="诊断体系"
|
||||
prop="diagnosisSystem"
|
||||
width="120"
|
||||
>
|
||||
<template #default="scope">
|
||||
<el-select
|
||||
v-model="scope.row.diagnosisSystem"
|
||||
placeholder=" "
|
||||
style="width: 100%"
|
||||
@change="handleDiagnosisSystemChange(scope.row)"
|
||||
>
|
||||
<el-option
|
||||
label="西医"
|
||||
value="西医"
|
||||
/>
|
||||
<el-option
|
||||
label="中医"
|
||||
value="中医"
|
||||
/>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="诊断类别"
|
||||
prop="classification"
|
||||
width="120"
|
||||
>
|
||||
<template #default="scope">
|
||||
<el-select
|
||||
v-model="scope.row.classification"
|
||||
placeholder=" "
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in diag_type"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="name"
|
||||
label="诊断名称"
|
||||
prop="name"
|
||||
width="180"
|
||||
>
|
||||
<template #default="scope">
|
||||
<div
|
||||
class="diagnosis-text"
|
||||
@click="handleDiagnosisNameClick(scope.row, scope.$index)"
|
||||
>
|
||||
<span class="diagnosis-text-content">{{ scope.row.name || '点击选择诊断' }}</span>
|
||||
<el-icon class="diagnosis-text-icon">
|
||||
<arrow-down />
|
||||
</el-icon>
|
||||
</div>
|
||||
<el-popover
|
||||
v-if="scope.row.showPopover"
|
||||
placement="bottom"
|
||||
:width="400"
|
||||
trigger="manual"
|
||||
>
|
||||
<template #reference>
|
||||
<span />
|
||||
</template>
|
||||
<div class="diagnosis-popover-container">
|
||||
<div class="diagnosis-popover-header">
|
||||
<span class="diagnosis-popover-title">选择诊断</span>
|
||||
<el-link
|
||||
type="primary"
|
||||
class="diagnosis-popover-close"
|
||||
@click="closeDiagnosisPopover(scope.row)"
|
||||
>
|
||||
关闭
|
||||
</el-link>
|
||||
</div>
|
||||
<div class="diagnosis-popover-body">
|
||||
<diagnosislist
|
||||
:diagnosis-searchkey="diagnosisSearchkey"
|
||||
@select-diagnosis="(row) => handleSelectDiagnosis(row, scope.row, scope.$index)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</el-popover>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="中医证候"
|
||||
prop="tcmSyndromeName"
|
||||
width="180"
|
||||
>
|
||||
<template #default="scope">
|
||||
<template v-if="scope.row.diagnosisSystem === '中医'">
|
||||
<div
|
||||
class="diagnosis-text"
|
||||
@click="handleTcmSyndromeClick(scope.row, scope.$index)"
|
||||
>
|
||||
<span class="diagnosis-text-content">{{ scope.row.tcmSyndromeName || '请选择中医证候' }}</span>
|
||||
<el-icon class="diagnosis-text-icon">
|
||||
<arrow-down />
|
||||
</el-icon>
|
||||
</div>
|
||||
<el-popover
|
||||
v-if="scope.row.showSyndromePopover"
|
||||
placement="bottom"
|
||||
:width="400"
|
||||
trigger="manual"
|
||||
>
|
||||
<template #reference>
|
||||
<span />
|
||||
</template>
|
||||
<div class="diagnosis-popover-container">
|
||||
<div class="diagnosis-popover-header">
|
||||
<span class="diagnosis-popover-title">选择中医证候</span>
|
||||
<el-link
|
||||
type="primary"
|
||||
class="diagnosis-popover-close"
|
||||
@click="closeSyndromePopover(scope.row)"
|
||||
>
|
||||
关闭
|
||||
</el-link>
|
||||
</div>
|
||||
<div class="diagnosis-popover-body">
|
||||
<el-input
|
||||
v-model="syndromeSearchkey"
|
||||
placeholder="搜索证候名称"
|
||||
clearable
|
||||
style="margin-bottom: 8px"
|
||||
@input="handleSyndromeSearch"
|
||||
/>
|
||||
<el-table
|
||||
:data="filteredSyndromeList"
|
||||
highlight-current-row
|
||||
max-height="300"
|
||||
@row-click="(row) => handleSelectSyndrome(row, scope.row)"
|
||||
>
|
||||
<el-table-column
|
||||
label="证候名称"
|
||||
prop="name"
|
||||
align="center"
|
||||
/>
|
||||
<el-table-column
|
||||
label="医保编码"
|
||||
prop="ybNo"
|
||||
align="center"
|
||||
prop="address"
|
||||
label="主诊"
|
||||
/>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
</el-popover>
|
||||
</template>
|
||||
<span v-else>—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="address"
|
||||
label="复诊"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="address"
|
||||
label="疑似"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="address"
|
||||
label="传染"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="address"
|
||||
label="入院病情"
|
||||
prop="admissionCondition"
|
||||
width="120"
|
||||
width="180"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="address"
|
||||
label="转归"
|
||||
prop="outcome"
|
||||
width="120"
|
||||
width="180"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="address"
|
||||
label="转归日期"
|
||||
prop="outcomeDate"
|
||||
width="140"
|
||||
width="180"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="address"
|
||||
label="诊断科室"
|
||||
prop="deptName"
|
||||
width="140"
|
||||
width="180"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="address"
|
||||
label="诊断医师"
|
||||
prop="diagnosisDoctor"
|
||||
width="140"
|
||||
width="180"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="address"
|
||||
label="诊断日期"
|
||||
prop="diagnosisTime"
|
||||
width="140"
|
||||
width="180"
|
||||
/>
|
||||
<el-table-column
|
||||
fixed="right"
|
||||
label="操作"
|
||||
width="120"
|
||||
>
|
||||
<template #default="scope">
|
||||
<template #default="props">
|
||||
<el-space>
|
||||
<el-tooltip
|
||||
content="删除"
|
||||
placement="bottom"
|
||||
>
|
||||
<el-icon @click="deleteRow(scope.row, scope.$index)">
|
||||
<el-icon @click="deleteDiagnose(row)">
|
||||
<Delete />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
v-if="scope.$index !== diagnoseData.length - 1"
|
||||
v-if="props.$index !== diagnoseData.length - 1"
|
||||
content="下移"
|
||||
placement="bottom"
|
||||
>
|
||||
<el-icon @click="moveDown(scope.row, scope.$index)">
|
||||
<el-icon @click="download(props.row)">
|
||||
<Download />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
v-if="scope.$index !== 0"
|
||||
v-if="props.$index !== 0"
|
||||
content="上移"
|
||||
placement="bottom"
|
||||
>
|
||||
<el-icon @click="moveUp(scope.row, scope.$index)">
|
||||
<el-icon @click="upload(props.row)">
|
||||
<Upload />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
v-if="props.$index !== 0"
|
||||
content="置顶"
|
||||
placement="bottom"
|
||||
>
|
||||
<el-icon @click="top(props.row)">
|
||||
<Top />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
v-if="props.$index !== diagnoseData.length - 1"
|
||||
content="置底"
|
||||
placement="bottom"
|
||||
>
|
||||
<el-icon @click="bottom(props.row)">
|
||||
<Bottom />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</el-space>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
<WesternMedicineDialog v-model:visible="westernMedicineDialogVisible" />
|
||||
<ChineseMedicineDialog
|
||||
v-model:visible="chineseMedicineDialogVisible"
|
||||
:patient-info="patientInfo"
|
||||
@ok-act="loadDiagnosisData"
|
||||
/>
|
||||
<WesternMedicineDialog v-model:visible="WesternMedicineDialogVisible" />
|
||||
<ChineseMedicineDialog v-model:visible="ChineseMedicineDialogVisible" />
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import {onMounted, reactive, ref, computed} from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { ArrowDown, Delete, Download, Upload } from '@element-plus/icons-vue'
|
||||
import {onBeforeMount, onMounted, reactive, ref} from 'vue'
|
||||
// const { proxy } = getCurrentInstance()
|
||||
// const emits = defineEmits([])
|
||||
// const props = defineProps({})
|
||||
// import DiagnoseFolder from './diagnoseFolder.vue'
|
||||
import WesternMedicineDialog from './westernMedicineDialog.vue'
|
||||
import ChineseMedicineDialog from './chineseMedicineDialog.vue'
|
||||
import Diagnosislist from './diagnosislist.vue'
|
||||
import {
|
||||
saveDiagnosis,
|
||||
delEncounterDiagnosis,
|
||||
getEncounterDiagnosis,
|
||||
getTcmSyndrome,
|
||||
} from '../api'
|
||||
|
||||
const { proxy } = getCurrentInstance()
|
||||
|
||||
const props = defineProps({
|
||||
patientInfo: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
const diagnoseData = ref([
|
||||
{
|
||||
id: 1,
|
||||
sort: 1,
|
||||
name: '新冠',
|
||||
},
|
||||
})
|
||||
{
|
||||
id: 2,
|
||||
sort: 2,
|
||||
name: '新冠as',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
sort: 3,
|
||||
name: '新冠12',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
sort: 4,
|
||||
name: '新冠2121',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
sort: 5,
|
||||
name: '新冠12',
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
sort: 6,
|
||||
name: '新冠21',
|
||||
},
|
||||
])
|
||||
|
||||
const diagnoseData = ref([])
|
||||
const selectedRows = ref([])
|
||||
const saveLoading = ref(false)
|
||||
const diagnoseTableRef = ref()
|
||||
const diagnosisSearchkey = ref('')
|
||||
const syndromeSearchkey = ref('')
|
||||
const syndromeList = ref([])
|
||||
|
||||
// 获取诊断类型字典(住院诊断类别)
|
||||
const { diag_type } = proxy.useDict('diag_type')
|
||||
|
||||
const filteredSyndromeList = computed(() => {
|
||||
if (!syndromeSearchkey.value) {
|
||||
return syndromeList.value
|
||||
}
|
||||
const keyword = syndromeSearchkey.value.toLowerCase()
|
||||
return syndromeList.value.filter(item =>
|
||||
(item.name && item.name.toLowerCase().includes(keyword)) ||
|
||||
(item.ybNo && item.ybNo.toLowerCase().includes(keyword))
|
||||
)
|
||||
})
|
||||
|
||||
function getCurrentDate() {
|
||||
const date = new Date()
|
||||
const year = date.getFullYear()
|
||||
let month = date.getMonth() + 1
|
||||
let day = date.getDate()
|
||||
month = month < 10 ? '0' + month : month
|
||||
day = day < 10 ? '0' + day : day
|
||||
return `${year}-${month}-${day}`
|
||||
}
|
||||
|
||||
function addNewDiagnosis() {
|
||||
const maxSortNo = diagnoseData.value.length > 0
|
||||
? Math.max(...diagnoseData.value.map(item => item.sortNo || 0))
|
||||
: 0
|
||||
diagnoseData.value.push({
|
||||
id: Date.now(),
|
||||
sortNo: maxSortNo + 1,
|
||||
diagnosisSystem: '西医',
|
||||
classification: '主诊断',
|
||||
name: '',
|
||||
ybNo: '',
|
||||
definitionId: '',
|
||||
tcmSyndromeCode: '',
|
||||
tcmSyndromeName: '',
|
||||
admissionCondition: '',
|
||||
outcome: '',
|
||||
outcomeDate: '',
|
||||
deptName: '',
|
||||
diagnosisDoctor: proxy.$store?.state?.user?.name || '',
|
||||
diagnosisTime: getCurrentDate(),
|
||||
showPopover: false,
|
||||
showSyndromePopover: false,
|
||||
isNew: true,
|
||||
})
|
||||
}
|
||||
|
||||
function addNewChinese() {
|
||||
chineseMedicineDialogVisible.value = true
|
||||
}
|
||||
|
||||
function handleDiagnosisSystemChange(row) {
|
||||
if (row.diagnosisSystem === '西医') {
|
||||
row.tcmSyndromeCode = ''
|
||||
row.tcmSyndromeName = ''
|
||||
}
|
||||
row.name = ''
|
||||
row.ybNo = ''
|
||||
row.showPopover = false
|
||||
row.showSyndromePopover = false
|
||||
}
|
||||
|
||||
function handleDiagnosisNameClick(row, index) {
|
||||
if (row.diagnosisSystem === '中医') {
|
||||
row.showPopover = false
|
||||
return
|
||||
}
|
||||
diagnoseData.value.forEach((item, idx) => {
|
||||
if (idx !== index) {
|
||||
item.showPopover = false
|
||||
}
|
||||
})
|
||||
row.showPopover = true
|
||||
}
|
||||
|
||||
function handleSelectDiagnosis(diagRow, rowData) {
|
||||
rowData.name = diagRow.name
|
||||
rowData.ybNo = diagRow.ybNo
|
||||
rowData.definitionId = diagRow.id
|
||||
rowData.showPopover = false
|
||||
}
|
||||
|
||||
function closeDiagnosisPopover(row) {
|
||||
row.showPopover = false
|
||||
}
|
||||
|
||||
function handleTcmSyndromeClick(row, index) {
|
||||
diagnoseData.value.forEach((item, idx) => {
|
||||
if (idx !== index) {
|
||||
item.showSyndromePopover = false
|
||||
}
|
||||
})
|
||||
loadSyndromeList()
|
||||
row.showSyndromePopover = true
|
||||
}
|
||||
|
||||
function handleSyndromeSearch() {}
|
||||
|
||||
function loadSyndromeList() {
|
||||
getTcmSyndrome().then((res) => {
|
||||
if (res.data && res.data.records) {
|
||||
syndromeList.value = res.data.records
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function handleSelectSyndrome(syndromeRow, rowData) {
|
||||
rowData.tcmSyndromeCode = syndromeRow.ybNo
|
||||
rowData.tcmSyndromeName = syndromeRow.name
|
||||
rowData.showSyndromePopover = false
|
||||
}
|
||||
|
||||
function closeSyndromePopover(row) {
|
||||
row.showSyndromePopover = false
|
||||
}
|
||||
|
||||
function handleSelectionChange(rows) {
|
||||
selectedRows.value = rows
|
||||
}
|
||||
|
||||
function deleteRow(row, index) {
|
||||
diagnoseData.value.splice(index, 1)
|
||||
}
|
||||
|
||||
function moveDown(row, index) {
|
||||
if (index >= diagnoseData.value.length - 1) return
|
||||
const temp = diagnoseData.value[index]
|
||||
diagnoseData.value[index] = diagnoseData.value[index + 1]
|
||||
diagnoseData.value[index + 1] = temp
|
||||
diagnoseData.value = [...diagnoseData.value]
|
||||
}
|
||||
|
||||
function moveUp(row, index) {
|
||||
if (index <= 0) return
|
||||
const temp = diagnoseData.value[index]
|
||||
diagnoseData.value[index] = diagnoseData.value[index - 1]
|
||||
diagnoseData.value[index - 1] = temp
|
||||
diagnoseData.value = [...diagnoseData.value]
|
||||
}
|
||||
|
||||
function handleDelete() {
|
||||
if (!selectedRows.value.length) {
|
||||
ElMessage.warning('请先选择要删除的诊断')
|
||||
return
|
||||
}
|
||||
ElMessageBox.confirm('确定删除选中的诊断吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
}).then(() => {
|
||||
const deleteIds = selectedRows.value
|
||||
.filter(item => item.conditionId)
|
||||
.map(item => item.conditionId)
|
||||
const newRows = selectedRows.value.filter(item => !item.conditionId)
|
||||
|
||||
newRows.forEach(item => {
|
||||
const idx = diagnoseData.value.findIndex(d => d.id === item.id)
|
||||
if (idx > -1) {
|
||||
diagnoseData.value.splice(idx, 1)
|
||||
}
|
||||
})
|
||||
|
||||
deleteIds.forEach(id => {
|
||||
delEncounterDiagnosis(id).then(() => {
|
||||
const idx = diagnoseData.value.findIndex(d => d.conditionId === id)
|
||||
if (idx > -1) {
|
||||
diagnoseData.value.splice(idx, 1)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
selectedRows.value = []
|
||||
ElMessage.success('删除成功')
|
||||
}).catch(() => {})
|
||||
}
|
||||
|
||||
async function handleSaveDiagnosis() {
|
||||
if (!diagnoseData.value.length) {
|
||||
ElMessage.warning('没有需要保存的诊断')
|
||||
return
|
||||
}
|
||||
|
||||
for (let i = 0; i < diagnoseData.value.length; i++) {
|
||||
const item = diagnoseData.value[i]
|
||||
if (!item.name) {
|
||||
ElMessage.warning(`第${i + 1}行诊断名称不能为空`)
|
||||
return
|
||||
}
|
||||
if (item.diagnosisSystem === '中医' && !item.tcmSyndromeCode) {
|
||||
ElMessage.error('中医诊断不完整,请录入对应的证候!')
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
saveLoading.value = true
|
||||
try {
|
||||
const diagnosisList = diagnoseData.value.map((item, index) => ({
|
||||
conditionId: item.conditionId || '',
|
||||
ybNo: item.ybNo || '',
|
||||
name: item.name,
|
||||
definitionId: item.definitionId || '',
|
||||
classification: item.classification || '主诊断',
|
||||
diagnosisSystem: item.diagnosisSystem || '西医',
|
||||
tcmSyndromeCode: item.tcmSyndromeCode || '',
|
||||
tcmSyndromeName: item.tcmSyndromeName || '',
|
||||
admissionCondition: item.admissionCondition || '',
|
||||
outcome: item.outcome || '',
|
||||
outcomeDate: item.outcomeDate || '',
|
||||
diagnosisDoctor: item.diagnosisDoctor || '',
|
||||
diagnosisTime: item.diagnosisTime || getCurrentDate(),
|
||||
diagSrtNo: index + 1,
|
||||
}))
|
||||
|
||||
const saveData = {
|
||||
patientId: props.patientInfo?.patientId || '',
|
||||
encounterId: props.patientInfo?.encounterId || '',
|
||||
diagnosisList: diagnosisList,
|
||||
}
|
||||
|
||||
const res = await saveDiagnosis(saveData)
|
||||
if (res.code === 200) {
|
||||
ElMessage.success('诊断保存成功')
|
||||
loadDiagnosisData()
|
||||
} else {
|
||||
ElMessage.error(res.msg || '保存失败')
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error('保存失败,请重试')
|
||||
} finally {
|
||||
saveLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function loadDiagnosisData() {
|
||||
if (!props.patientInfo?.encounterId) return
|
||||
getEncounterDiagnosis(props.patientInfo.encounterId).then((res) => {
|
||||
if (res.data) {
|
||||
const westernDiagnoses = (res.data || []).filter(item => item.typeName !== '中医诊断')
|
||||
diagnoseData.value = westernDiagnoses.map((item, index) => ({
|
||||
...item,
|
||||
diagnosisSystem: item.diagnosisSystem || '西医',
|
||||
classification: item.classification || '主诊断',
|
||||
tcmSyndromeCode: item.tcmSyndromeCode || '',
|
||||
tcmSyndromeName: item.tcmSyndromeName || '',
|
||||
showPopover: false,
|
||||
showSyndromePopover: false,
|
||||
diagSrtNo: index + 1,
|
||||
}))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 模拟数据(常用/科室/个人/历史诊断树)
|
||||
// 模拟数据
|
||||
const mockData = ref([
|
||||
{
|
||||
name: '常用',
|
||||
@@ -587,18 +207,28 @@ const mockData = ref([
|
||||
{
|
||||
name: '文件夹 1',
|
||||
children: [
|
||||
{ name: '霍乱' },
|
||||
{ name: '新型冠状病毒' },
|
||||
{
|
||||
name: '霍乱',
|
||||
},
|
||||
{
|
||||
name: '新型冠状病毒新型冠状病毒新型冠状病毒',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: '文件夹 2',
|
||||
children: [
|
||||
{ name: '普外科' },
|
||||
{ name: '骨科' },
|
||||
{
|
||||
name: '普外科',
|
||||
},
|
||||
{
|
||||
name: '骨科',
|
||||
},
|
||||
],
|
||||
},
|
||||
{ name: '新型冠状病毒' },
|
||||
{
|
||||
name: '新型冠状病毒',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -607,18 +237,28 @@ const mockData = ref([
|
||||
{
|
||||
name: '内科',
|
||||
children: [
|
||||
{ name: '呼吸内科' },
|
||||
{ name: '消化内科' },
|
||||
{
|
||||
name: '呼吸内科',
|
||||
},
|
||||
{
|
||||
name: '消化内科',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: '外科',
|
||||
children: [
|
||||
{ name: '普外科' },
|
||||
{ name: '骨科' },
|
||||
{
|
||||
name: '普外科',
|
||||
},
|
||||
{
|
||||
name: '骨科',
|
||||
},
|
||||
],
|
||||
},
|
||||
{ name: '儿科' },
|
||||
{
|
||||
name: '儿科',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -627,27 +267,79 @@ const mockData = ref([
|
||||
{
|
||||
name: '内科',
|
||||
children: [
|
||||
{ name: '呼吸内科' },
|
||||
{ name: '消化内科' },
|
||||
{
|
||||
name: '呼吸内科',
|
||||
},
|
||||
{
|
||||
name: '消化内科',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: '外科',
|
||||
children: [
|
||||
{
|
||||
name: '普外科',
|
||||
},
|
||||
{
|
||||
name: '骨科',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: '儿科',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: '历史',
|
||||
children: [
|
||||
{ name: '心率失常' },
|
||||
{
|
||||
name: '心率失常',
|
||||
},
|
||||
{
|
||||
name: '心率失常',
|
||||
},
|
||||
{
|
||||
name: '心率失常',
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
|
||||
const state = reactive({})
|
||||
onMounted(() => {
|
||||
if (props.patientInfo?.encounterId) {
|
||||
loadDiagnosisData()
|
||||
onBeforeMount(() => {})
|
||||
onMounted(() => {})
|
||||
defineExpose({ state })
|
||||
|
||||
// const deleteDiagnose = (row: any) => {
|
||||
// // TODO 删除
|
||||
// console.log(row)
|
||||
// }
|
||||
|
||||
// const download = (row: any) => {
|
||||
// // TODO 删除
|
||||
// }
|
||||
|
||||
// const upload = (row: any) => {
|
||||
// // TODO 删除
|
||||
// }
|
||||
|
||||
// const top = (row: any) => {
|
||||
// // TODO 删除
|
||||
// }
|
||||
|
||||
// const bottom = (row: any) => {
|
||||
// // TODO 删除
|
||||
// }
|
||||
|
||||
const addNewWestern = () => {
|
||||
WesternMedicineDialogVisible.value = true
|
||||
}
|
||||
})
|
||||
defineExpose({ state, loadDiagnosisData })
|
||||
const addNewChinese = () => {
|
||||
ChineseMedicineDialogVisible.value = true
|
||||
}
|
||||
const WesternMedicineDialogVisible = ref(false)
|
||||
const ChineseMedicineDialogVisible = ref(false)
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.diagnose-container {
|
||||
@@ -673,79 +365,4 @@ defineExpose({ state, loadDiagnosisData })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.diagnosis-text {
|
||||
min-height: 32px;
|
||||
line-height: 1.4;
|
||||
padding: 6px 12px;
|
||||
border: 1px solid #dcdfe6;
|
||||
border-radius: 4px;
|
||||
background-color: #fff;
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
word-break: break-all;
|
||||
white-space: pre-wrap;
|
||||
max-width: 200px;
|
||||
transition: border-color 0.2s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.diagnosis-text:hover {
|
||||
border-color: #409eff;
|
||||
}
|
||||
|
||||
.diagnosis-text-content {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.diagnosis-text-icon {
|
||||
color: #909399;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.diagnosis-text:hover .diagnosis-text-icon {
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
.diagnosis-popover-container {
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.diagnosis-popover-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 12px 16px;
|
||||
border-bottom: 1px solid #e4e7ed;
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
|
||||
.diagnosis-popover-title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.diagnosis-popover-close {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.diagnosis-popover-body {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.diagnosis-text:empty::before {
|
||||
content: '点击选择诊断';
|
||||
color: #a8abb2;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -287,7 +287,7 @@
|
||||
<el-table-column label="药房/科室" align="center" prop="" width="240">
|
||||
<template #default="scope">
|
||||
<span v-if="!scope.row.isEdit">
|
||||
{{ scope.row.positionName || scope.row.orgName }}
|
||||
{{ scope.row.positionName }}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
@@ -111,7 +111,6 @@ function handleClick(tabName) {
|
||||
break;
|
||||
case 'cancel':
|
||||
exeStatus.value = 9;
|
||||
requestStatus.value = RequestStatus.CANCELLED;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -2339,10 +2339,6 @@ function handleMedicalAdvice(row) {
|
||||
const draftItems = filteredItems.filter(item => item.statusEnum === 1)
|
||||
const activeItems = filteredItems.filter(item => item.statusEnum === 2)
|
||||
|
||||
if (activeItems.length > 0) {
|
||||
temporarySigned.value = true
|
||||
}
|
||||
|
||||
// 🔧 修复:限制返回数量,最多显示前100条,避免数据过多导致页面卡死
|
||||
const maxItems = 100
|
||||
if (draftItems.length > maxItems) {
|
||||
@@ -2418,9 +2414,9 @@ function handleMedicalAdvice(row) {
|
||||
const contentData = jsonContent ? JSON.parse(jsonContent) : {};
|
||||
const medicineName = contentData.adviceName || contentData.advice_name || item.adviceName || item.advice_name || '';
|
||||
const spec = contentData.volume || contentData.specification || item.volume || item.specification || '';
|
||||
const specMatch = spec.match(/([\d.]+)\s*([a-zA-Z一-龥]+)/)
|
||||
const specValue = specMatch ? parseFloat(specMatch[1]) : 1
|
||||
const specUnit = specMatch ? specMatch[2] : ''
|
||||
const specMatch = spec.match(/(\d+)(\D+)/)
|
||||
const specValue = specMatch ? parseInt(specMatch[1]) : 1
|
||||
const specUnit = specMatch ? specMatch[2] : 'ml'
|
||||
const dosage = specValue * (contentData.quantity || item.quantity || 1)
|
||||
|
||||
let usageCode = contentData.methodCode || 'iv'
|
||||
@@ -2438,8 +2434,8 @@ function handleMedicalAdvice(row) {
|
||||
unit: specUnit,
|
||||
usage: usageCode,
|
||||
usageLabel,
|
||||
frequency: '立即',
|
||||
executeTime: '',
|
||||
frequency: '临时',
|
||||
executeTime: new Date().toLocaleString('zh-CN'),
|
||||
originalMedicine: {
|
||||
...item,
|
||||
medicineName: medicineName,
|
||||
@@ -2453,8 +2449,8 @@ function handleMedicalAdvice(row) {
|
||||
id: index + 1,
|
||||
adviceName: item.adviceName || item.advice_name || '',
|
||||
dosage: 1, unit: 'ml', usage: 'iv', usageLabel: '静脉注射',
|
||||
frequency: '立即',
|
||||
executeTime: '',
|
||||
frequency: '临时',
|
||||
executeTime: new Date().toLocaleString('zh-CN'),
|
||||
originalMedicine: {
|
||||
...item,
|
||||
medicineName: item.adviceName || item.advice_name || '',
|
||||
@@ -2588,14 +2584,14 @@ function handleTemporaryMedicalSubmit(data) {
|
||||
let usageCode = contentData.methodCode || 'iv'
|
||||
return {
|
||||
id: index + 1, adviceName: medicineName, dosage, unit: specUnit,
|
||||
usage: usageCode, frequency: '立即',
|
||||
executeTime: '',
|
||||
usage: usageCode, frequency: '临时',
|
||||
executeTime: new Date().toLocaleString('zh-CN'),
|
||||
originalMedicine: { ...item, medicineName, specification: spec, quantity: contentData.quantity || item.quantity || 1, encounterId: row.visitId }
|
||||
}
|
||||
} catch (e) {
|
||||
return {
|
||||
id: index + 1, adviceName: item.adviceName || '', dosage: 1, unit: 'ml',
|
||||
usage: 'iv', frequency: '立即', executeTime: '',
|
||||
usage: 'iv', frequency: '临时', executeTime: new Date().toLocaleString('zh-CN'),
|
||||
originalMedicine: { ...item, medicineName: item.adviceName || '', specification: item.volume || '', quantity: item.quantity || 1, encounterId: row.visitId }
|
||||
}
|
||||
}
|
||||
@@ -2709,8 +2705,8 @@ function handleQuoteBilling() {
|
||||
else if (usageCode === 'po' && (medicineName.includes('片') || medicineName.includes('胶囊'))) { usageLabel = '口服' }
|
||||
return {
|
||||
id: index + 1, adviceName: medicineName, dosage, unit: specUnit,
|
||||
usage: usageCode, usageLabel, frequency: '立即',
|
||||
executeTime: '',
|
||||
usage: usageCode, usageLabel, frequency: '临时',
|
||||
executeTime: new Date().toLocaleString('zh-CN'),
|
||||
originalMedicine: {
|
||||
...item,
|
||||
medicineName: medicineName,
|
||||
@@ -2723,7 +2719,7 @@ function handleQuoteBilling() {
|
||||
return {
|
||||
id: index + 1, adviceName: item.adviceName || item.advice_name || '',
|
||||
dosage: 1, unit: 'ml', usage: 'iv', usageLabel: '静脉注射',
|
||||
frequency: '立即', executeTime: '',
|
||||
frequency: '临时', executeTime: new Date().toLocaleString('zh-CN'),
|
||||
originalMedicine: {
|
||||
...item,
|
||||
medicineName: item.adviceName || item.advice_name || '',
|
||||
|
||||
@@ -173,8 +173,6 @@
|
||||
border
|
||||
style="width: 100%;"
|
||||
fit
|
||||
highlight-current-row
|
||||
@row-click="handleAdviceRowClick"
|
||||
>
|
||||
<el-table-column
|
||||
label="序号"
|
||||
@@ -259,7 +257,7 @@
|
||||
<span
|
||||
class="info-value"
|
||||
:class="{ 'unsigned': !isSigned }"
|
||||
>{{ isSigned ? signatureDoctor : '未签名' }}</span>
|
||||
>{{ isSigned ? currentUser.name : '未签名' }}</span>
|
||||
</div>
|
||||
<div class="signature-info">
|
||||
<span class="info-label">签名时间:</span>
|
||||
@@ -400,7 +398,6 @@ import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import useUserStore from '@/store/modules/user'
|
||||
import { checkPassword } from '@/api/surgicalschedule'
|
||||
import { savePrescription } from '@/views/clinicmanagement/bargain/component/api.js'
|
||||
import { parseTime } from '@/utils/openhis'
|
||||
|
||||
// 定义props
|
||||
const props = defineProps({
|
||||
@@ -510,11 +507,16 @@ const displayAdvicesList = computed(() => {
|
||||
return advicesExpanded.value ? all : all.slice(0, PAGE_SIZE)
|
||||
})
|
||||
|
||||
const isSigned = ref(false)
|
||||
// 响应式数据 - isSigned 从父组件传入的 prop 初始化
|
||||
const isSigned = ref(props.isSignedProp)
|
||||
|
||||
// 🔧 修复 Bug #446: 同步父组件 isSignedProp 的变化到本地 isSigned
|
||||
// ref(props.isSignedProp) 只在初始化时读取一次,父组件后续更新不会自动同步
|
||||
watch(() => props.isSignedProp, (newVal) => {
|
||||
isSigned.value = newVal
|
||||
})
|
||||
|
||||
const signatureDoctor = ref(userStore.nickName || userStore.name || '未知用户')
|
||||
const signatureTime = ref('')
|
||||
|
||||
const showSignDialog = ref(false)
|
||||
const signPassword = ref('')
|
||||
const showEditDialog = ref(false)
|
||||
@@ -529,7 +531,7 @@ const editForm = ref({
|
||||
|
||||
// 计算属性
|
||||
const currentUser = computed(() => ({
|
||||
name: userStore.nickName || userStore.name || '未知用户',
|
||||
name: userStore.name || '未知用户',
|
||||
id: userStore.id
|
||||
}))
|
||||
|
||||
@@ -552,10 +554,10 @@ const totalAmount = computed(() => {
|
||||
// 将计费药品转换为临时医嘱数据
|
||||
const convertedAdvices = computed(() => {
|
||||
return props.billingMedicines.map((medicine, index) => {
|
||||
// 解析规格中的数值和单位(支持小数,去除 ×、:、/、* 等多余字符)
|
||||
const specMatch = medicine.specification ? medicine.specification.match(/([\d.]+)\s*([a-zA-Z一-龥]+)/) : null
|
||||
const specValue = specMatch ? parseFloat(specMatch[1]) : 1
|
||||
const specUnit = specMatch ? specMatch[2] : ''
|
||||
// 解析规格中的数值和单位
|
||||
const specMatch = medicine.specification ? medicine.specification.match(/(\d+)(\D+)/) : null
|
||||
const specValue = specMatch ? parseInt(specMatch[1]) : 1
|
||||
const specUnit = specMatch ? specMatch[2] : 'ml'
|
||||
|
||||
// 计算剂量 = 规格数值 × 数量
|
||||
const dosage = specValue * (medicine.quantity || 1)
|
||||
@@ -581,8 +583,8 @@ const convertedAdvices = computed(() => {
|
||||
unit: specUnit,
|
||||
usage: usageCode, // 🔧 修复:使用后端字典的正确编码
|
||||
usageLabel: usageLabel, // 🔧 新增:保存显示名称
|
||||
frequency: '立即',
|
||||
executeTime: '',
|
||||
frequency: '临时',
|
||||
executeTime: new Date().toLocaleString('zh-CN'),
|
||||
originalMedicine: medicine
|
||||
}
|
||||
})
|
||||
@@ -638,24 +640,6 @@ const handleSign = () => {
|
||||
showSignDialog.value = true
|
||||
}
|
||||
|
||||
// 点击已生成列表行 → 回显该行的签名信息
|
||||
const handleAdviceRowClick = (row) => {
|
||||
const om = row?.originalMedicine
|
||||
if (!om) return
|
||||
const contentJson = om.contentJson || om.content_json
|
||||
if (!contentJson) return
|
||||
try {
|
||||
const cd = typeof contentJson === 'string' ? JSON.parse(contentJson) : contentJson
|
||||
if (cd.signDoctorName) {
|
||||
signatureDoctor.value = cd.signDoctorName
|
||||
}
|
||||
if (cd.signDate) {
|
||||
signatureTime.value = cd.signDate
|
||||
}
|
||||
isSigned.value = true
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
// 编辑医嘱
|
||||
const handleEditAdvice = (index) => {
|
||||
const advice = displayAdvices.value[index]
|
||||
@@ -678,7 +662,7 @@ const handleEditAdvice = (index) => {
|
||||
}
|
||||
|
||||
// 保存编辑
|
||||
const handleSaveEdit = async () => {
|
||||
const handleSaveEdit = () => {
|
||||
if (!editForm.value.dosage && editForm.value.dosage !== 0) {
|
||||
ElMessage.warning('请填写剂量')
|
||||
return
|
||||
@@ -736,8 +720,8 @@ const handleSaveEdit = async () => {
|
||||
|
||||
// 如果用户修改了剂量,重新计算数量
|
||||
if (originalMedicine.specification) {
|
||||
const specMatch = originalMedicine.specification.match(/([\d.]+)\s*([a-zA-Z一-龥]+)/)
|
||||
const specValue = specMatch ? parseFloat(specMatch[1]) : 1
|
||||
const specMatch = originalMedicine.specification.match(/(\d+)(\D+)/)
|
||||
const specValue = specMatch ? parseInt(specMatch[1]) : 1
|
||||
if (specValue > 0) {
|
||||
const newQuantity = editForm.value.dosage / specValue
|
||||
contentData.quantity = newQuantity
|
||||
@@ -748,8 +732,11 @@ const handleSaveEdit = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
// 🔧 修复:原地修改 contentJson,保存使用最新数据
|
||||
originalMedicine.contentJson = JSON.stringify(contentData)
|
||||
// 更新 contentJson
|
||||
updatedAdvice.originalMedicine = {
|
||||
...originalMedicine,
|
||||
contentJson: JSON.stringify(contentData)
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('解析 originalMedicine.contentJson 失败', e)
|
||||
}
|
||||
@@ -763,49 +750,7 @@ const handleSaveEdit = async () => {
|
||||
emit('update:temporary-advices', updatedAdvices)
|
||||
|
||||
showEditDialog.value = false
|
||||
|
||||
// 🔧 修复 Bug #604: 编辑保存后直接提交到服务器
|
||||
const editMedicine = updatedAdvice.originalMedicine
|
||||
if (editMedicine) {
|
||||
let contentJsonData = {}
|
||||
try { contentJsonData = JSON.parse(editMedicine.contentJson || '{}') } catch (e) {}
|
||||
const quantity = editMedicine.quantity || contentJsonData.quantity || 1
|
||||
const unitPrice = editMedicine.unitPrice || contentJsonData.unitPrice || 0
|
||||
contentJsonData.dose = editForm.value.dosage
|
||||
contentJsonData.doseUnitCode = editForm.value.unit
|
||||
contentJsonData.methodCode = updatedAdvice.usage
|
||||
contentJsonData.quantity = quantity
|
||||
contentJsonData.totalPrice = unitPrice * quantity
|
||||
contentJsonData.adviceName = updatedAdvice.adviceName
|
||||
|
||||
const saveItem = {
|
||||
...contentJsonData,
|
||||
dbOpType: editMedicine.requestId ? '2' : '1',
|
||||
adviceType: editMedicine.adviceType || 1,
|
||||
requestId: editMedicine.requestId,
|
||||
chargeItemId: editMedicine.chargeItemId,
|
||||
contentJson: JSON.stringify(contentJsonData),
|
||||
quantity,
|
||||
unitCode: editMedicine.unitCode || editForm.value.unit,
|
||||
unitPrice,
|
||||
totalPrice: unitPrice * quantity,
|
||||
adviceName: updatedAdvice.adviceName,
|
||||
patientId: props.patientInfo.patientId,
|
||||
encounterId: props.patientInfo.visitId,
|
||||
orgId: props.patientInfo.orgId,
|
||||
methodCode: updatedAdvice.usage,
|
||||
dose: editForm.value.dosage,
|
||||
doseUnitCode: editForm.value.unit,
|
||||
generateSourceEnum: 6,
|
||||
sourceBillNo: props.patientInfo?.operCode || ''
|
||||
}
|
||||
try {
|
||||
await savePrescription({ organizationId: props.patientInfo.orgId || 1, adviceSaveList: [saveItem] }, '2')
|
||||
ElMessage.success('医嘱修改已保存到服务器')
|
||||
} catch (e) {
|
||||
ElMessage.error('保存失败,请重试')
|
||||
}
|
||||
}
|
||||
ElMessage.success('编辑成功(已暂存本地,请点击"一键签名并生成医嘱"按钮提交到服务器)')
|
||||
}
|
||||
|
||||
// 取消编辑
|
||||
@@ -817,7 +762,7 @@ const handleCancelEdit = () => {
|
||||
dosage: '',
|
||||
unit: '',
|
||||
usage: '',
|
||||
frequency: '立即'
|
||||
frequency: '临时'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -832,10 +777,10 @@ const confirmSign = async () => {
|
||||
const response = await checkPassword({
|
||||
password: signPassword.value
|
||||
})
|
||||
|
||||
if (response.code === 200 && response.data) {
|
||||
isSigned.value = true
|
||||
signatureDoctor.value = userStore.nickName || userStore.name
|
||||
signatureTime.value = parseTime(new Date())
|
||||
signatureTime.value = new Date().toLocaleString('zh-CN')
|
||||
showSignDialog.value = false
|
||||
signPassword.value = ''
|
||||
ElMessage.success('签名成功')
|
||||
@@ -854,8 +799,10 @@ const confirmSign = async () => {
|
||||
|
||||
const handleSignAndSubmit = () => {
|
||||
if (isSigned.value) {
|
||||
// 如果已经签名,直接提交
|
||||
handleSubmit()
|
||||
} else {
|
||||
// 如果未签名,打开签名弹窗
|
||||
handleSign()
|
||||
}
|
||||
}
|
||||
@@ -960,8 +907,6 @@ const handleSubmit = async () => {
|
||||
contentJsonData.dose = advice.dosage;
|
||||
contentJsonData.doseUnitCode = advice.unit;
|
||||
contentJsonData.rateCode = advice.frequency;
|
||||
contentJsonData.signDoctorName = signatureDoctor.value
|
||||
contentJsonData.signDate = signatureTime.value
|
||||
|
||||
// 重新序列化contentJson
|
||||
const updatedContentJson = JSON.stringify(contentJsonData);
|
||||
@@ -1048,7 +993,7 @@ const handleSubmit = async () => {
|
||||
billingMedicines: props.billingMedicines,
|
||||
temporaryAdvices: itemsToSign,
|
||||
signature: {
|
||||
doctorName: signatureDoctor.value,
|
||||
doctorName: currentUser.value.name,
|
||||
signatureTime: signatureTime.value
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { LoginPage } from '../pages/LoginPage';
|
||||
|
||||
/**
|
||||
* Bug #466: Bug #466 待确认标题
|
||||
* 自动生成: 2026-06-01 09:36:17
|
||||
*/
|
||||
test.describe('🐛 Bug#466', () => {
|
||||
let loginPage: LoginPage;
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
loginPage = new LoginPage(page);
|
||||
await loginPage.goto();
|
||||
await loginPage.login(
|
||||
process.env.TEST_USERNAME || 'admin',
|
||||
process.env.TEST_PASSWORD || 'admin123'
|
||||
);
|
||||
await loginPage.expectLoginSuccess();
|
||||
});
|
||||
|
||||
test('#466 Bug #466 待确认标题 @bug466 @regression', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
|
||||
// 检查页面正常加载(非登录页)
|
||||
await expect(page).not.toHaveURL(/.*login.*/);
|
||||
|
||||
// 检查无 JS 错误
|
||||
const jsErrors: string[] = [];
|
||||
page.on('pageerror', (err) => jsErrors.push(err.message));
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 页面基本可交互
|
||||
const body = page.locator('body');
|
||||
await expect(body).toBeVisible();
|
||||
|
||||
// 截图记录
|
||||
await page.screenshot({
|
||||
path: 'tests/e2e/report/bug-466-result.png',
|
||||
fullPage: true
|
||||
});
|
||||
|
||||
// 无 JS 错误
|
||||
expect(jsErrors).toEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -1,47 +0,0 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { LoginPage } from '../pages/LoginPage';
|
||||
|
||||
/**
|
||||
* Bug #467: Bug #467 待确认标题
|
||||
* 自动生成: 2026-06-01 09:36:17
|
||||
*/
|
||||
test.describe('🐛 Bug#467', () => {
|
||||
let loginPage: LoginPage;
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
loginPage = new LoginPage(page);
|
||||
await loginPage.goto();
|
||||
await loginPage.login(
|
||||
process.env.TEST_USERNAME || 'admin',
|
||||
process.env.TEST_PASSWORD || 'admin123'
|
||||
);
|
||||
await loginPage.expectLoginSuccess();
|
||||
});
|
||||
|
||||
test('#467 Bug #467 待确认标题 @bug467 @regression', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
|
||||
// 检查页面正常加载(非登录页)
|
||||
await expect(page).not.toHaveURL(/.*login.*/);
|
||||
|
||||
// 检查无 JS 错误
|
||||
const jsErrors: string[] = [];
|
||||
page.on('pageerror', (err) => jsErrors.push(err.message));
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 页面基本可交互
|
||||
const body = page.locator('body');
|
||||
await expect(body).toBeVisible();
|
||||
|
||||
// 截图记录
|
||||
await page.screenshot({
|
||||
path: 'tests/e2e/report/bug-467-result.png',
|
||||
fullPage: true
|
||||
});
|
||||
|
||||
// 无 JS 错误
|
||||
expect(jsErrors).toEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -1,47 +0,0 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { LoginPage } from '../pages/LoginPage';
|
||||
|
||||
/**
|
||||
* Bug #610: Bug #610 待确认标题
|
||||
* 自动生成: 2026-06-01 09:36:17
|
||||
*/
|
||||
test.describe('🐛 Bug#610', () => {
|
||||
let loginPage: LoginPage;
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
loginPage = new LoginPage(page);
|
||||
await loginPage.goto();
|
||||
await loginPage.login(
|
||||
process.env.TEST_USERNAME || 'admin',
|
||||
process.env.TEST_PASSWORD || 'admin123'
|
||||
);
|
||||
await loginPage.expectLoginSuccess();
|
||||
});
|
||||
|
||||
test('#610 Bug #610 待确认标题 @bug610 @regression', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
|
||||
// 检查页面正常加载(非登录页)
|
||||
await expect(page).not.toHaveURL(/.*login.*/);
|
||||
|
||||
// 检查无 JS 错误
|
||||
const jsErrors: string[] = [];
|
||||
page.on('pageerror', (err) => jsErrors.push(err.message));
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 页面基本可交互
|
||||
const body = page.locator('body');
|
||||
await expect(body).toBeVisible();
|
||||
|
||||
// 截图记录
|
||||
await page.screenshot({
|
||||
path: 'tests/e2e/report/bug-610-result.png',
|
||||
fullPage: true
|
||||
});
|
||||
|
||||
// 无 JS 错误
|
||||
expect(jsErrors).toEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -1,47 +0,0 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { LoginPage } from '../pages/LoginPage';
|
||||
|
||||
/**
|
||||
* Bug #611: Bug #611 待确认标题
|
||||
* 自动生成: 2026-06-01 09:36:17
|
||||
*/
|
||||
test.describe('🐛 Bug#611', () => {
|
||||
let loginPage: LoginPage;
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
loginPage = new LoginPage(page);
|
||||
await loginPage.goto();
|
||||
await loginPage.login(
|
||||
process.env.TEST_USERNAME || 'admin',
|
||||
process.env.TEST_PASSWORD || 'admin123'
|
||||
);
|
||||
await loginPage.expectLoginSuccess();
|
||||
});
|
||||
|
||||
test('#611 Bug #611 待确认标题 @bug611 @regression', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
|
||||
// 检查页面正常加载(非登录页)
|
||||
await expect(page).not.toHaveURL(/.*login.*/);
|
||||
|
||||
// 检查无 JS 错误
|
||||
const jsErrors: string[] = [];
|
||||
page.on('pageerror', (err) => jsErrors.push(err.message));
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 页面基本可交互
|
||||
const body = page.locator('body');
|
||||
await expect(body).toBeVisible();
|
||||
|
||||
// 截图记录
|
||||
await page.screenshot({
|
||||
path: 'tests/e2e/report/bug-611-result.png',
|
||||
fullPage: true
|
||||
});
|
||||
|
||||
// 无 JS 错误
|
||||
expect(jsErrors).toEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -1,47 +0,0 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { LoginPage } from '../pages/LoginPage';
|
||||
|
||||
/**
|
||||
* Bug #613: Bug #613 待确认标题
|
||||
* 自动生成: 2026-06-01 09:36:17
|
||||
*/
|
||||
test.describe('🐛 Bug#613', () => {
|
||||
let loginPage: LoginPage;
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
loginPage = new LoginPage(page);
|
||||
await loginPage.goto();
|
||||
await loginPage.login(
|
||||
process.env.TEST_USERNAME || 'admin',
|
||||
process.env.TEST_PASSWORD || 'admin123'
|
||||
);
|
||||
await loginPage.expectLoginSuccess();
|
||||
});
|
||||
|
||||
test('#613 Bug #613 待确认标题 @bug613 @regression', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
|
||||
// 检查页面正常加载(非登录页)
|
||||
await expect(page).not.toHaveURL(/.*login.*/);
|
||||
|
||||
// 检查无 JS 错误
|
||||
const jsErrors: string[] = [];
|
||||
page.on('pageerror', (err) => jsErrors.push(err.message));
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 页面基本可交互
|
||||
const body = page.locator('body');
|
||||
await expect(body).toBeVisible();
|
||||
|
||||
// 截图记录
|
||||
await page.screenshot({
|
||||
path: 'tests/e2e/report/bug-613-result.png',
|
||||
fullPage: true
|
||||
});
|
||||
|
||||
// 无 JS 错误
|
||||
expect(jsErrors).toEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -1,47 +0,0 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { LoginPage } from '../pages/LoginPage';
|
||||
|
||||
/**
|
||||
* Bug #614: Bug #614 待确认标题
|
||||
* 自动生成: 2026-06-01 09:36:18
|
||||
*/
|
||||
test.describe('🐛 Bug#614', () => {
|
||||
let loginPage: LoginPage;
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
loginPage = new LoginPage(page);
|
||||
await loginPage.goto();
|
||||
await loginPage.login(
|
||||
process.env.TEST_USERNAME || 'admin',
|
||||
process.env.TEST_PASSWORD || 'admin123'
|
||||
);
|
||||
await loginPage.expectLoginSuccess();
|
||||
});
|
||||
|
||||
test('#614 Bug #614 待确认标题 @bug614 @regression', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
|
||||
// 检查页面正常加载(非登录页)
|
||||
await expect(page).not.toHaveURL(/.*login.*/);
|
||||
|
||||
// 检查无 JS 错误
|
||||
const jsErrors: string[] = [];
|
||||
page.on('pageerror', (err) => jsErrors.push(err.message));
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 页面基本可交互
|
||||
const body = page.locator('body');
|
||||
await expect(body).toBeVisible();
|
||||
|
||||
// 截图记录
|
||||
await page.screenshot({
|
||||
path: 'tests/e2e/report/bug-614-result.png',
|
||||
fullPage: true
|
||||
});
|
||||
|
||||
// 无 JS 错误
|
||||
expect(jsErrors).toEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -1,47 +0,0 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { LoginPage } from '../pages/LoginPage';
|
||||
|
||||
/**
|
||||
* Bug #615: Bug #615 待确认标题
|
||||
* 自动生成: 2026-06-01 09:36:18
|
||||
*/
|
||||
test.describe('🐛 Bug#615', () => {
|
||||
let loginPage: LoginPage;
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
loginPage = new LoginPage(page);
|
||||
await loginPage.goto();
|
||||
await loginPage.login(
|
||||
process.env.TEST_USERNAME || 'admin',
|
||||
process.env.TEST_PASSWORD || 'admin123'
|
||||
);
|
||||
await loginPage.expectLoginSuccess();
|
||||
});
|
||||
|
||||
test('#615 Bug #615 待确认标题 @bug615 @regression', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
|
||||
// 检查页面正常加载(非登录页)
|
||||
await expect(page).not.toHaveURL(/.*login.*/);
|
||||
|
||||
// 检查无 JS 错误
|
||||
const jsErrors: string[] = [];
|
||||
page.on('pageerror', (err) => jsErrors.push(err.message));
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 页面基本可交互
|
||||
const body = page.locator('body');
|
||||
await expect(body).toBeVisible();
|
||||
|
||||
// 截图记录
|
||||
await page.screenshot({
|
||||
path: 'tests/e2e/report/bug-615-result.png',
|
||||
fullPage: true
|
||||
});
|
||||
|
||||
// 无 JS 错误
|
||||
expect(jsErrors).toEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -1,47 +0,0 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { LoginPage } from '../pages/LoginPage';
|
||||
|
||||
/**
|
||||
* Bug #616: Bug #616 待确认标题
|
||||
* 自动生成: 2026-06-01 09:36:18
|
||||
*/
|
||||
test.describe('🐛 Bug#616', () => {
|
||||
let loginPage: LoginPage;
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
loginPage = new LoginPage(page);
|
||||
await loginPage.goto();
|
||||
await loginPage.login(
|
||||
process.env.TEST_USERNAME || 'admin',
|
||||
process.env.TEST_PASSWORD || 'admin123'
|
||||
);
|
||||
await loginPage.expectLoginSuccess();
|
||||
});
|
||||
|
||||
test('#616 Bug #616 待确认标题 @bug616 @regression', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
|
||||
// 检查页面正常加载(非登录页)
|
||||
await expect(page).not.toHaveURL(/.*login.*/);
|
||||
|
||||
// 检查无 JS 错误
|
||||
const jsErrors: string[] = [];
|
||||
page.on('pageerror', (err) => jsErrors.push(err.message));
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 页面基本可交互
|
||||
const body = page.locator('body');
|
||||
await expect(body).toBeVisible();
|
||||
|
||||
// 截图记录
|
||||
await page.screenshot({
|
||||
path: 'tests/e2e/report/bug-616-result.png',
|
||||
fullPage: true
|
||||
});
|
||||
|
||||
// 无 JS 错误
|
||||
expect(jsErrors).toEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -1,47 +0,0 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { LoginPage } from '../pages/LoginPage';
|
||||
|
||||
/**
|
||||
* Bug #625: Bug #625 待确认标题
|
||||
* 自动生成: 2026-06-01 09:36:18
|
||||
*/
|
||||
test.describe('🐛 Bug#625', () => {
|
||||
let loginPage: LoginPage;
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
loginPage = new LoginPage(page);
|
||||
await loginPage.goto();
|
||||
await loginPage.login(
|
||||
process.env.TEST_USERNAME || 'admin',
|
||||
process.env.TEST_PASSWORD || 'admin123'
|
||||
);
|
||||
await loginPage.expectLoginSuccess();
|
||||
});
|
||||
|
||||
test('#625 Bug #625 待确认标题 @bug625 @regression', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
|
||||
// 检查页面正常加载(非登录页)
|
||||
await expect(page).not.toHaveURL(/.*login.*/);
|
||||
|
||||
// 检查无 JS 错误
|
||||
const jsErrors: string[] = [];
|
||||
page.on('pageerror', (err) => jsErrors.push(err.message));
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 页面基本可交互
|
||||
const body = page.locator('body');
|
||||
await expect(body).toBeVisible();
|
||||
|
||||
// 截图记录
|
||||
await page.screenshot({
|
||||
path: 'tests/e2e/report/bug-625-result.png',
|
||||
fullPage: true
|
||||
});
|
||||
|
||||
// 无 JS 错误
|
||||
expect(jsErrors).toEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -1,47 +0,0 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { LoginPage } from '../pages/LoginPage';
|
||||
|
||||
/**
|
||||
* Bug #626: Bug #626 待确认标题
|
||||
* 自动生成: 2026-06-01 09:36:18
|
||||
*/
|
||||
test.describe('🐛 Bug#626', () => {
|
||||
let loginPage: LoginPage;
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
loginPage = new LoginPage(page);
|
||||
await loginPage.goto();
|
||||
await loginPage.login(
|
||||
process.env.TEST_USERNAME || 'admin',
|
||||
process.env.TEST_PASSWORD || 'admin123'
|
||||
);
|
||||
await loginPage.expectLoginSuccess();
|
||||
});
|
||||
|
||||
test('#626 Bug #626 待确认标题 @bug626 @regression', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
|
||||
// 检查页面正常加载(非登录页)
|
||||
await expect(page).not.toHaveURL(/.*login.*/);
|
||||
|
||||
// 检查无 JS 错误
|
||||
const jsErrors: string[] = [];
|
||||
page.on('pageerror', (err) => jsErrors.push(err.message));
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 页面基本可交互
|
||||
const body = page.locator('body');
|
||||
await expect(body).toBeVisible();
|
||||
|
||||
// 截图记录
|
||||
await page.screenshot({
|
||||
path: 'tests/e2e/report/bug-626-result.png',
|
||||
fullPage: true
|
||||
});
|
||||
|
||||
// 无 JS 错误
|
||||
expect(jsErrors).toEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -1,47 +0,0 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { LoginPage } from '../pages/LoginPage';
|
||||
|
||||
/**
|
||||
* Bug #627: Bug #627 待确认标题
|
||||
* 自动生成: 2026-06-01 09:36:18
|
||||
*/
|
||||
test.describe('🐛 Bug#627', () => {
|
||||
let loginPage: LoginPage;
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
loginPage = new LoginPage(page);
|
||||
await loginPage.goto();
|
||||
await loginPage.login(
|
||||
process.env.TEST_USERNAME || 'admin',
|
||||
process.env.TEST_PASSWORD || 'admin123'
|
||||
);
|
||||
await loginPage.expectLoginSuccess();
|
||||
});
|
||||
|
||||
test('#627 Bug #627 待确认标题 @bug627 @regression', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
|
||||
// 检查页面正常加载(非登录页)
|
||||
await expect(page).not.toHaveURL(/.*login.*/);
|
||||
|
||||
// 检查无 JS 错误
|
||||
const jsErrors: string[] = [];
|
||||
page.on('pageerror', (err) => jsErrors.push(err.message));
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 页面基本可交互
|
||||
const body = page.locator('body');
|
||||
await expect(body).toBeVisible();
|
||||
|
||||
// 截图记录
|
||||
await page.screenshot({
|
||||
path: 'tests/e2e/report/bug-627-result.png',
|
||||
fullPage: true
|
||||
});
|
||||
|
||||
// 无 JS 错误
|
||||
expect(jsErrors).toEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -1,47 +0,0 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { LoginPage } from '../pages/LoginPage';
|
||||
|
||||
/**
|
||||
* Bug #628: Bug #628 待确认标题
|
||||
* 自动生成: 2026-06-01 09:36:18
|
||||
*/
|
||||
test.describe('🐛 Bug#628', () => {
|
||||
let loginPage: LoginPage;
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
loginPage = new LoginPage(page);
|
||||
await loginPage.goto();
|
||||
await loginPage.login(
|
||||
process.env.TEST_USERNAME || 'admin',
|
||||
process.env.TEST_PASSWORD || 'admin123'
|
||||
);
|
||||
await loginPage.expectLoginSuccess();
|
||||
});
|
||||
|
||||
test('#628 Bug #628 待确认标题 @bug628 @regression', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
|
||||
// 检查页面正常加载(非登录页)
|
||||
await expect(page).not.toHaveURL(/.*login.*/);
|
||||
|
||||
// 检查无 JS 错误
|
||||
const jsErrors: string[] = [];
|
||||
page.on('pageerror', (err) => jsErrors.push(err.message));
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 页面基本可交互
|
||||
const body = page.locator('body');
|
||||
await expect(body).toBeVisible();
|
||||
|
||||
// 截图记录
|
||||
await page.screenshot({
|
||||
path: 'tests/e2e/report/bug-628-result.png',
|
||||
fullPage: true
|
||||
});
|
||||
|
||||
// 无 JS 错误
|
||||
expect(jsErrors).toEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -1,47 +0,0 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { LoginPage } from '../pages/LoginPage';
|
||||
|
||||
/**
|
||||
* Bug #629: Bug #629 待确认标题
|
||||
* 自动生成: 2026-06-01 09:36:18
|
||||
*/
|
||||
test.describe('🐛 Bug#629', () => {
|
||||
let loginPage: LoginPage;
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
loginPage = new LoginPage(page);
|
||||
await loginPage.goto();
|
||||
await loginPage.login(
|
||||
process.env.TEST_USERNAME || 'admin',
|
||||
process.env.TEST_PASSWORD || 'admin123'
|
||||
);
|
||||
await loginPage.expectLoginSuccess();
|
||||
});
|
||||
|
||||
test('#629 Bug #629 待确认标题 @bug629 @regression', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
|
||||
// 检查页面正常加载(非登录页)
|
||||
await expect(page).not.toHaveURL(/.*login.*/);
|
||||
|
||||
// 检查无 JS 错误
|
||||
const jsErrors: string[] = [];
|
||||
page.on('pageerror', (err) => jsErrors.push(err.message));
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 页面基本可交互
|
||||
const body = page.locator('body');
|
||||
await expect(body).toBeVisible();
|
||||
|
||||
// 截图记录
|
||||
await page.screenshot({
|
||||
path: 'tests/e2e/report/bug-629-result.png',
|
||||
fullPage: true
|
||||
});
|
||||
|
||||
// 无 JS 错误
|
||||
expect(jsErrors).toEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -1,47 +0,0 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { LoginPage } from '../pages/LoginPage';
|
||||
|
||||
/**
|
||||
* Bug #630: Bug #630 待确认标题
|
||||
* 自动生成: 2026-06-01 09:36:18
|
||||
*/
|
||||
test.describe('🐛 Bug#630', () => {
|
||||
let loginPage: LoginPage;
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
loginPage = new LoginPage(page);
|
||||
await loginPage.goto();
|
||||
await loginPage.login(
|
||||
process.env.TEST_USERNAME || 'admin',
|
||||
process.env.TEST_PASSWORD || 'admin123'
|
||||
);
|
||||
await loginPage.expectLoginSuccess();
|
||||
});
|
||||
|
||||
test('#630 Bug #630 待确认标题 @bug630 @regression', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
|
||||
// 检查页面正常加载(非登录页)
|
||||
await expect(page).not.toHaveURL(/.*login.*/);
|
||||
|
||||
// 检查无 JS 错误
|
||||
const jsErrors: string[] = [];
|
||||
page.on('pageerror', (err) => jsErrors.push(err.message));
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 页面基本可交互
|
||||
const body = page.locator('body');
|
||||
await expect(body).toBeVisible();
|
||||
|
||||
// 截图记录
|
||||
await page.screenshot({
|
||||
path: 'tests/e2e/report/bug-630-result.png',
|
||||
fullPage: true
|
||||
});
|
||||
|
||||
// 无 JS 错误
|
||||
expect(jsErrors).toEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -1,98 +0,0 @@
|
||||
#!/bin/bash
|
||||
# 为指定 Bug 生成 Playwright 测试用例
|
||||
# 用法: ./generate-bug-test.sh <bug_id> <bug_title> [bug_steps]
|
||||
|
||||
BUG_ID="$1"
|
||||
BUG_TITLE="$2"
|
||||
BUG_STEPS="$3"
|
||||
|
||||
if [ -z "$BUG_ID" ] || [ -z "$BUG_TITLE" ]; then
|
||||
echo "用法: $0 <bug_id> <bug_title> [bug_steps]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SPEC_DIR="$(dirname "$0")/../specs"
|
||||
SPEC_FILE="${SPEC_DIR}/bug-${BUG_ID}.spec.ts"
|
||||
|
||||
# 如果测试已存在,跳过
|
||||
if [ -f "$SPEC_FILE" ]; then
|
||||
echo "SKIP: ${SPEC_FILE} 已存在"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
mkdir -p "$SPEC_DIR"
|
||||
|
||||
# 从标题推断模块
|
||||
infer_route() {
|
||||
local t="$1"
|
||||
if echo "$t" | grep -qi "门诊医生\|门诊诊前\|门诊挂号"; then echo "/doctorstation"; return; fi
|
||||
if echo "$t" | grep -qi "住院医生\|临床医嘱\|医嘱录入"; then echo "/inpatientDoctor"; return; fi
|
||||
if echo "$t" | grep -qi "住院护士\|补费\|发退药\|医嘱执行"; then echo "/inpatientNurse"; return; fi
|
||||
if echo "$t" | grep -qi "分诊\|排队\|候诊"; then echo "/triageandqueuemanage"; return; fi
|
||||
if echo "$t" | grep -qi "挂号\|预约\|签到"; then echo "/registration"; return; fi
|
||||
if echo "$t" | grep -qi "手术\|计费"; then echo "/operatingroom"; return; fi
|
||||
if echo "$t" | grep -qi "诊断\|中医"; then echo "/inpatientDoctor"; return; fi
|
||||
if echo "$t" | grep -qi "病历\|EMR"; then echo "/doctorstation"; return; fi
|
||||
if echo "$t" | grep -qi "目录\|诊疗"; then echo "/catalog"; return; fi
|
||||
if echo "$t" | grep -qi "药房\|发药\|库存"; then echo "/pharmacy"; return; fi
|
||||
echo "/"
|
||||
}
|
||||
|
||||
ROUTE=$(infer_route "$BUG_TITLE")
|
||||
STEPS_COMMENT=""
|
||||
if [ -n "$BUG_STEPS" ]; then
|
||||
STEPS_COMMENT="// 复现步骤:
|
||||
// $(echo "$BUG_STEPS" | head -5)"
|
||||
fi
|
||||
|
||||
cat > "$SPEC_FILE" << SPECEOF
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { LoginPage } from '../pages/LoginPage';
|
||||
|
||||
/**
|
||||
* Bug #${BUG_ID}: ${BUG_TITLE}
|
||||
* 自动生成: $(date '+%Y-%m-%d %H:%M:%S')
|
||||
*/
|
||||
test.describe('🐛 Bug#${BUG_ID}', () => {
|
||||
let loginPage: LoginPage;
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
loginPage = new LoginPage(page);
|
||||
await loginPage.goto();
|
||||
await loginPage.login(
|
||||
process.env.TEST_USERNAME || 'admin',
|
||||
process.env.TEST_PASSWORD || 'admin123'
|
||||
);
|
||||
await loginPage.expectLoginSuccess();
|
||||
});
|
||||
|
||||
test('#${BUG_ID} ${BUG_TITLE} @bug${BUG_ID} @regression', async ({ page }) => {
|
||||
await page.goto('${ROUTE}');
|
||||
await page.waitForLoadState('networkidle');
|
||||
${STEPS_COMMENT}
|
||||
|
||||
// 检查页面正常加载(非登录页)
|
||||
await expect(page).not.toHaveURL(/.*login.*/);
|
||||
|
||||
// 检查无 JS 错误
|
||||
const jsErrors: string[] = [];
|
||||
page.on('pageerror', (err) => jsErrors.push(err.message));
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 页面基本可交互
|
||||
const body = page.locator('body');
|
||||
await expect(body).toBeVisible();
|
||||
|
||||
// 截图记录
|
||||
await page.screenshot({
|
||||
path: 'tests/e2e/report/bug-${BUG_ID}-result.png',
|
||||
fullPage: true
|
||||
});
|
||||
|
||||
// 无 JS 错误
|
||||
expect(jsErrors).toEqual([]);
|
||||
});
|
||||
});
|
||||
SPECEOF
|
||||
|
||||
echo "OK: ${SPEC_FILE}"
|
||||
@@ -1,191 +0,0 @@
|
||||
/**
|
||||
* Bug 回归测试用例生成器
|
||||
*
|
||||
* 根据 Bug 标题、描述、复现步骤自动生成 Playwright 测试用例。
|
||||
* 每个 Bug 生成独立的 spec 文件:tests/e2e/specs/bug-{id}.spec.ts
|
||||
*/
|
||||
|
||||
export interface BugInfo {
|
||||
id: string;
|
||||
title: string;
|
||||
description?: string;
|
||||
steps?: string;
|
||||
module?: string;
|
||||
severity?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 Bug 标题推断所属模块和页面路径
|
||||
*/
|
||||
function inferModule(title: string): { page: string; route: string; description: string } {
|
||||
const t = title.toLowerCase();
|
||||
|
||||
if (t.includes('门诊医生') || t.includes('门诊诊前') || t.includes('门诊挂号')) {
|
||||
return { page: '门诊医生站', route: '/doctorstation', description: '门诊医生工作站' };
|
||||
}
|
||||
if (t.includes('住院医生') || t.includes('临床医嘱') || t.includes('医嘱录入')) {
|
||||
return { page: '住院医生站', route: '/inpatientDoctor', description: '住院医生工作站' };
|
||||
}
|
||||
if (t.includes('住院护士') || t.includes('补费') || t.includes('发退药') || t.includes('医嘱执行')) {
|
||||
return { page: '住院护士站', route: '/inpatientNurse', description: '住院护士工作站' };
|
||||
}
|
||||
if (t.includes('分诊') || t.includes('排队') || t.includes('候诊')) {
|
||||
return { page: '分诊台', route: '/triageandqueuemanage', description: '分诊排队管理' };
|
||||
}
|
||||
if (t.includes('挂号') || t.includes('预约') || t.includes('签到')) {
|
||||
return { page: '挂号', route: '/registration', description: '门诊挂号' };
|
||||
}
|
||||
if (t.includes('手术') || t.includes('计费')) {
|
||||
return { page: '手术管理', route: '/operatingroom', description: '手术管理/计费' };
|
||||
}
|
||||
if (t.includes('诊断') || t.includes('中医')) {
|
||||
return { page: '诊断录入', route: '/inpatientDoctor', description: '诊断录入模块' };
|
||||
}
|
||||
if (t.includes('病历') || t.includes('EMR') || t.includes('emr')) {
|
||||
return { page: '病历', route: '/doctorstation', description: '电子病历' };
|
||||
}
|
||||
if (t.includes('目录') || t.includes('诊疗')) {
|
||||
return { page: '目录管理', route: '/catalog', description: '诊疗目录管理' };
|
||||
}
|
||||
if (t.includes('药房') || t.includes('发药') || t.includes('库存')) {
|
||||
return { page: '药房管理', route: '/pharmacy', description: '药房管理' };
|
||||
}
|
||||
|
||||
return { page: '未知模块', route: '/', description: '通用模块' };
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 Bug 标题推断需要测试的关键操作
|
||||
*/
|
||||
function inferTestActions(title: string): string[] {
|
||||
const actions: string[] = [];
|
||||
const t = title.toLowerCase();
|
||||
|
||||
if (t.includes('报错') || t.includes('错误') || t.includes('异常')) {
|
||||
actions.push('检查页面无 JS 错误');
|
||||
actions.push('检查控制台无报错');
|
||||
}
|
||||
if (t.includes('显示') || t.includes('缺失') || t.includes('不规范')) {
|
||||
actions.push('检查元素正确显示');
|
||||
actions.push('检查数据完整性');
|
||||
}
|
||||
if (t.includes('弹窗') || t.includes('弹框')) {
|
||||
actions.push('检查弹窗正常弹出');
|
||||
actions.push('检查弹窗内容正确');
|
||||
}
|
||||
if (t.includes('保存') || t.includes('提交') || t.includes('写入')) {
|
||||
actions.push('检查保存操作成功');
|
||||
actions.push('检查数据持久化');
|
||||
}
|
||||
if (t.includes('列表') || t.includes('查询')) {
|
||||
actions.push('检查列表数据加载');
|
||||
actions.push('检查分页功能');
|
||||
}
|
||||
if (t.includes('按钮') || t.includes('操作')) {
|
||||
actions.push('检查按钮可点击');
|
||||
actions.push('检查操作响应');
|
||||
}
|
||||
if (t.includes('下拉') || t.includes('选择') || t.includes('字典')) {
|
||||
actions.push('检查下拉选项加载');
|
||||
actions.push('检查选项值正确');
|
||||
}
|
||||
if (t.includes('退回') || t.includes('撤回') || t.includes('取消')) {
|
||||
actions.push('检查退回流程');
|
||||
actions.push('检查状态变更');
|
||||
}
|
||||
|
||||
// 至少有一个基础检查
|
||||
if (actions.length === 0) {
|
||||
actions.push('检查页面正常加载');
|
||||
actions.push('检查无明显异常');
|
||||
}
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 Playwright 测试用例代码
|
||||
*/
|
||||
export function generateBugTestSpec(bug: BugInfo): string {
|
||||
const mod = inferModule(bug.title);
|
||||
const actions = inferTestActions(bug.title);
|
||||
|
||||
const stepsComment = bug.steps
|
||||
? `\n // 复现步骤:\n // ${bug.steps.split('\n').join('\n // ')}`
|
||||
: '';
|
||||
|
||||
return `import { test, expect } from '@playwright/test';
|
||||
import { LoginPage } from '../pages/LoginPage';
|
||||
|
||||
/**
|
||||
* Bug #${bug.id}: ${bug.title}
|
||||
* 模块: ${mod.description}
|
||||
* 自动生成时间: ${new Date().toISOString()}
|
||||
* 严重程度: ${bug.severity || '未知'}
|
||||
*/
|
||||
test.describe('🐛 Bug#${bug.id} ${mod.description}', () => {
|
||||
let loginPage: LoginPage;
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
loginPage = new LoginPage(page);
|
||||
await loginPage.goto();
|
||||
await loginPage.login(
|
||||
process.env.TEST_USERNAME || 'admin',
|
||||
process.env.TEST_PASSWORD || 'admin123'
|
||||
);
|
||||
await loginPage.expectLoginSuccess();
|
||||
});
|
||||
|
||||
test('#${bug.id} ${bug.title} @bug${bug.id} @regression', async ({ page }) => {
|
||||
// 导航到目标页面
|
||||
await page.goto('${mod.route}');
|
||||
await page.waitForLoadState('networkidle');
|
||||
${stepsComment}
|
||||
|
||||
// ── 检查项 ──
|
||||
// 1. 页面正常加载
|
||||
await expect(page).not.toHaveURL(/.*login.*/);
|
||||
|
||||
// 2. 检查页面无 JS 错误
|
||||
const jsErrors: string[] = [];
|
||||
page.on('pageerror', (err) => jsErrors.push(err.message));
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 3. 执行具体检查
|
||||
${actions.map(a => ` // ${a}
|
||||
await page.waitForTimeout(500);`).join('\n')}
|
||||
|
||||
// 4. 断言:无 JS 错误
|
||||
expect(jsErrors).toEqual([]);
|
||||
|
||||
// 5. 截图记录
|
||||
await page.screenshot({
|
||||
path: 'tests/e2e/report/bug-${bug.id}-result.png',
|
||||
fullPage: true
|
||||
});
|
||||
});
|
||||
});
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将测试用例写入文件
|
||||
*/
|
||||
export function writeBugTestSpec(bug: BugInfo): string {
|
||||
const spec = generateBugTestSpec(bug);
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const specDir = path.join(__dirname, '..', 'specs');
|
||||
const filePath = path.join(specDir, `bug-${bug.id}.spec.ts`);
|
||||
|
||||
// 不覆盖已有测试
|
||||
if (fs.existsSync(filePath)) {
|
||||
return filePath;
|
||||
}
|
||||
|
||||
fs.mkdirSync(specDir, { recursive: true });
|
||||
fs.writeFileSync(filePath, spec, 'utf-8');
|
||||
|
||||
return filePath;
|
||||
}
|
||||
Reference in New Issue
Block a user