Compare commits

24 Commits

Author SHA1 Message Date
633cf2c17f 门诊医生站患者病历打不开 不显示数据问题 2025-12-16 17:12:21 +08:00
3188ca5752 build(openhis-ui-vue3): 更新 sass 依赖版本并注释部分路由配置
更新 sass 依赖从 ^1.70.0 到 ^1.77.8,并注释掉 router 中暂时未使用的路由配置项,
包括门诊医生站、套餐管理、预约管理、基础管理、维护系统及系统管理等相关路由。
2025-12-16 13:49:06 +08:00
py
c79e4c2623 需求27:增加挂号收费系统参数维护界面-》挂号处理相关参数 2025-12-16 13:33:50 +08:00
f3c451d0a1 解决首页和门诊挂号保存报错问题 2025-12-15 17:06:25 +08:00
a077bd57d4 预约管理->相关文件转移、号源后端接口实现、前端页面逻辑、数据处理修改。 2025-12-15 16:50:16 +08:00
cf16c497bd 修改路由配置 2025-12-15 16:05:16 +08:00
fd1ab239a9 门诊出诊医生诊室设置 2025-12-15 15:37:23 +08:00
caf65e3113 ```
feat(router): 优化路由配置与注释说明

- 重构 constantRoutes 和 dynamicRoutes 中的路由结构,提升可读性
- 补充详细的路由配置项注释,便于后续维护
- 添加路由名称检查避免重复添加相同路由
- 更新数据库连接地址及 Redis 配置信息
- 完善 .gitignore 忽略文件列表,排除临时文件和日志
```
2025-12-15 14:24:45 +08:00
c18c21ff4c ```
build(openhis-ui-vue3): 更新 package-lock.json 文件

添加 resolutions 字段以解决依赖版本冲突问题,包含 stable、source-map-url、
urix、resolve-url、source-map-resolve 和 sourcemap-codec 等依赖包的版本
锁定,确保项目构建稳定性。
```
2025-12-14 15:01:10 +08:00
ab6849c9eb 根据您提供的信息,没有实际的代码差异内容。但我可以为您提供一个符合Angular规范的commit message模板示例:
```
docs(changelog): 更新版本发布说明

添加新功能描述和bug修复记录到更新日志中,
确保所有重要的变更都已正确记录以便用户查阅。
```

如果您有具体的代码差异信息,请提供详细内容,我将为您生成更准确的commit message。
2025-12-14 14:53:10 +08:00
6b555f2563 fix(openhis-ui-vue3): 降级 element-plus-icons-vue 版本
将 @element-plus/icons-vue 从版本 2.5.0 降级到 2.3.2,以解决可能存在的兼容性问题或回退到稳定版本。
2025-12-14 14:53:02 +08:00
7645405c5b 更新组件 2025-12-14 14:44:43 +08:00
5bfadb9174 fix(login): 修复获取用户绑定租户列表时用户名为空导致的URL错误
确保username参数存在,避免因为空值造成接口调用失败

feat(editor): 重构富文本编辑器组件并优化图片上传逻辑
- 使用 Composition API 重构代码结构,提升可维护性
- 改进图片上传功能,增强对 quill 实例的安全访问
- 更新样式排版,提高组件可读性和一致性

refactor(file-upload): 移除旧代理引用,使用 modern Vue API
替换 `proxy` 调用为 `modal` 插件直接调用,提升代码清晰度与健壮性

refactor(image-upload): 替换旧实例调用方式,强化错误提示机制
统一使用 `modal` 进行消息提示和加载状态控制,改善用户体验

refactor(tree-select): 引入 Composition API 优化节点操作逻辑
移除 `getCurrentInstance` 的不必要使用,改为明确的模板引用管理

chore(main): 添加 util._extend 补丁以消除 Node.js 环境警告
解决开发环境下由于 Node.js 内建模块缺失造成的运行时警告问题

feat(template): 完善跌倒/坠床评估护理记录单模板
- 增加详细注释说明各部分作用,便于后续维护
- 明确组件名称为中文,利于业务识别
- 丰富表单交互细节及数据处理逻辑,支持动态打分、措施选择等功能

refactor(template-index): 加强模板组件自动注册逻辑
增加组件 name 属性校验,防止无效或匿名组件被注册到全局
2025-12-14 14:22:55 +08:00
e1b9d36153 feat(template): 添加股骨头坏死门诊病历模板
新增了一个名为“股骨头坏死(模板1)”的门诊病历模板文件,包含完整的主诉、现病史、既往史、体格检查、辅助检查、诊断和治疗方案等内容,便于医生快速调用和填写。

该模板位于 `src/template/股骨头坏死(模板1).vue`,采用 Vue 单文件组件格式编写,并定义了相应的结构与样式。
2025-12-13 22:23:58 +08:00
fdb8d6c934 更新模板注释测试中文名 2025-12-13 22:18:56 +08:00
22a1ac57b2 改回配置IP地址 2025-12-13 16:06:13 +08:00
4d243815a6 修正格式 2025-12-13 16:03:06 +08:00
882e8c9199 修正问题 2025-12-12 17:06:14 +08:00
a0c87f6335 问题关键 2025-12-12 17:01:24 +08:00
538dde55f7 还原门诊医生站 2025-12-12 15:57:03 +08:00
f33e3c6f15 首页报错和门诊医生站报错 2025-12-12 15:48:07 +08:00
0794782505 TypeScript Vue Plugi 2025-12-12 15:43:58 +08:00
d37fa46b5f 删除rabbitmq 2025-12-12 15:07:27 +08:00
8fcc229ad8 关联套餐设置页面对应字段 2025-12-12 10:59:22 +08:00
74 changed files with 4349 additions and 2082 deletions

4
.gitignore vendored
View File

@@ -58,3 +58,7 @@
PostgreSQL/openHis_DB设计书.xlsx PostgreSQL/openHis_DB设计书.xlsx
public.sql public.sql
发版记录/2025-11-12/~$发版日志.docx
发版记录/2025-11-12/~$S-管理系统-调价管理.docx
发版记录/2025-11-12/发版日志.docx
.gitignore

View File

@@ -62,10 +62,10 @@
<artifactId>httpclient</artifactId> <artifactId>httpclient</artifactId>
</dependency> </dependency>
<!-- rabbitMQ --> <!-- rabbitMQ -->
<dependency> <!-- <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId> <artifactId>spring-boot-starter-amqp</artifactId>
</dependency> </dependency> -->
</dependencies> </dependencies>

View File

@@ -1,7 +1,7 @@
package com.openhis.web.appointmentmanage.appservice; package com.openhis.web.appointmentmanage.appservice;
import com.core.common.core.domain.R; import com.core.common.core.domain.R;
import com.openhis.administration.domain.DoctorSchedule; import com.openhis.appointmentmanage.domain.DoctorSchedule;
public interface IDoctorScheduleAppService { public interface IDoctorScheduleAppService {

View File

@@ -0,0 +1,8 @@
package com.openhis.web.appointmentmanage.appservice;
import com.core.common.core.domain.R;
import com.openhis.web.appointmentmanage.dto.SchedulePoolDto;
public interface ISchedulePoolAppService {
R<?> addSchedulePool(SchedulePoolDto schedulePoolDto);
}

View File

@@ -0,0 +1,4 @@
package com.openhis.web.appointmentmanage.appservice;
public interface IScheduleSlotAppService {
}

View File

@@ -3,8 +3,8 @@ package com.openhis.web.appointmentmanage.appservice.impl;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.core.common.core.domain.R; import com.core.common.core.domain.R;
import com.openhis.administration.domain.Dept; import com.openhis.appointmentmanage.domain.Dept;
import com.openhis.administration.service.IDeptService; import com.openhis.appointmentmanage.service.IDeptService;
import com.openhis.web.appointmentmanage.appservice.IDeptAppService; import com.openhis.web.appointmentmanage.appservice.IDeptAppService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;

View File

@@ -2,8 +2,8 @@ package com.openhis.web.appointmentmanage.appservice.impl;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import com.core.common.core.domain.R; import com.core.common.core.domain.R;
import com.openhis.administration.domain.DoctorSchedule; import com.openhis.appointmentmanage.domain.DoctorSchedule;
import com.openhis.administration.service.IDoctorScheduleService; import com.openhis.appointmentmanage.service.IDoctorScheduleService;
import com.openhis.web.appointmentmanage.appservice.IDoctorScheduleAppService; import com.openhis.web.appointmentmanage.appservice.IDoctorScheduleAppService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;

View File

@@ -0,0 +1,41 @@
package com.openhis.web.appointmentmanage.appservice.impl;
import cn.hutool.core.util.ObjectUtil;
import com.core.common.core.domain.R;
import com.openhis.appointmentmanage.domain.SchedulePool;
import com.openhis.appointmentmanage.service.ISchedulePoolService;
import com.openhis.web.appointmentmanage.appservice.ISchedulePoolAppService;
import com.openhis.web.appointmentmanage.dto.SchedulePoolDto;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class SchedulePoolAppServiceImpl implements ISchedulePoolAppService {
@Resource
private ISchedulePoolService schedulePoolService;
@Override
public R<?> addSchedulePool(SchedulePoolDto schedulePoolDto) {
//12/15 实体封装过程数据关系复杂 尚未完全理清 下次继续改
if(ObjectUtil.isNull(schedulePoolDto)){
return R.fail("号源不能为空");
}
SchedulePool schedulePool = new SchedulePool();
schedulePool.setHospitalId(schedulePoolDto.getHospitalId());
schedulePool.setDeptId(schedulePoolDto.getDeptId());
schedulePool.setDoctorId(schedulePoolDto.getDoctorId());
schedulePool.setDoctorName(schedulePoolDto.getDoctorName());
schedulePool.setScheduleDate(schedulePoolDto.getScheduleDate());
schedulePool.setShift(schedulePoolDto.getShift());
schedulePool.setStartTime(schedulePoolDto.getStartTime());
schedulePool.setEndTime(schedulePoolDto.getEndTime());
schedulePool.setRegType(schedulePoolDto.getRegType());
schedulePool.setFee(schedulePoolDto.getFee());
boolean save = schedulePoolService.save(schedulePool);
return R.ok(save);
}
}

View File

@@ -0,0 +1,8 @@
package com.openhis.web.appointmentmanage.appservice.impl;
import com.openhis.web.appointmentmanage.appservice.IScheduleSlotAppService;
import org.springframework.stereotype.Service;
@Service
public class ScheduleSlotAppServiceImpl implements IScheduleSlotAppService {
}

View File

@@ -1,12 +1,11 @@
package com.openhis.web.appointmentmanage.controller; package com.openhis.web.appointmentmanage.controller;
import com.core.common.core.domain.R; import com.core.common.core.domain.R;
import com.openhis.administration.domain.DoctorSchedule; import com.openhis.appointmentmanage.domain.DoctorSchedule;
import com.openhis.web.appointmentmanage.appservice.IDoctorScheduleAppService; import com.openhis.web.appointmentmanage.appservice.IDoctorScheduleAppService;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.websocket.server.PathParam;
@RestController @RestController
@RequestMapping("/doctor-schedule") @RequestMapping("/doctor-schedule")

View File

@@ -0,0 +1,28 @@
package com.openhis.web.appointmentmanage.controller;
import com.core.common.core.domain.R;
import com.openhis.appointmentmanage.domain.SchedulePool;
import com.openhis.web.appointmentmanage.appservice.ISchedulePoolAppService;
import com.openhis.web.appointmentmanage.dto.SchedulePoolDto;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
@RequestMapping("/schedule-pool")
public class SchedulePoolController {
@Resource
private ISchedulePoolAppService schedulePoolAppService;
/*
* 新增号源
*
* */
public R<?> addSchedulePool(@RequestBody SchedulePoolDto schedulePoolDto) {
return R.ok(schedulePoolAppService.addSchedulePool(schedulePoolDto));
}
}

View File

@@ -0,0 +1,9 @@
package com.openhis.web.appointmentmanage.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/schedule-slot")
public class ScheduleSlotController {
}

View File

@@ -0,0 +1,104 @@
package com.openhis.web.appointmentmanage.dto;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.experimental.Accessors;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
/**
* 号源池Dto
*
* @date 2025-12-12
*/
@Data
public class SchedulePoolDto {
/** id */
private Integer id;
/** 业务编号 */
private String poolCode;
/** 医院ID */
private Integer hospitalId;
/** 科室ID */
private Integer deptId;
/** 医生ID */
private Integer doctorId;
/** 医生姓名 */
private String doctorName;
/** 诊室 */
private String clinicRoom;
/** 出诊日期 */
private LocalDate scheduleDate;
/** 班别 */
private String shift;
/** 开始时间 */
private LocalTime startTime;
/** 结束时间 */
private LocalTime endTime;
/** 总号量 */
private Integer totalQuota;
/** 已约 */
private Integer bookedNum;
/** 铁号数 */
private Integer lockedNum;
/** 剩余号数 */
private Integer availableNum;
/** 号别 */
private String regType;
/** 原价 (元) */
private Double fee;
/** 医保限价 (元) */
private Double insurancePrice;
/** 支持渠道 */
private String supportChannel;
/** 号源状态 */
private Integer status;
/** 停诊原因 */
private String stopReason;
/** 放号时间 */
private LocalDateTime releaseTime;
/** 截止预约时间 */
private LocalDateTime deadlineTime;
/** 乐观锁版本 */
private Integer version;
/** 操作人ID */
private Integer opUserId;
/** 备注 */
private String remark;
/** 排班ID */
private Integer scheduleId;
/** 创建时间 */
private LocalDateTime createTime;
/** 更新时间 */
private LocalDateTime updateTime;
}

View File

@@ -0,0 +1,7 @@
package com.openhis.web.appointmentmanage.mapper;
import org.springframework.stereotype.Repository;
@Repository
public interface SchedulePoolAppMapper {
}

View File

@@ -0,0 +1,7 @@
package com.openhis.web.appointmentmanage.mapper;
import org.springframework.stereotype.Repository;
@Repository
public interface ScheduleSlotAppMapper {
}

View File

@@ -179,7 +179,7 @@ public class DiagTreatMAppServiceImpl implements IDiagTreatMAppService {
// 分页查询 // 分页查询
IPage<DiagnosisTreatmentDto> diseaseTreatmentPage = IPage<DiagnosisTreatmentDto> diseaseTreatmentPage =
activityDefinitionManageMapper.getDiseaseTreatmentPage(new Page<>(pageNo, pageSize), queryWrapper); activityDefinitionManageMapper.getDiseaseTreatmentPage(new Page<DiagnosisTreatmentDto>(pageNo, pageSize), queryWrapper);
diseaseTreatmentPage.getRecords().forEach(e -> { diseaseTreatmentPage.getRecords().forEach(e -> {
// 医保标记枚举类回显赋值 // 医保标记枚举类回显赋值

View File

@@ -93,7 +93,14 @@
T13.charge_item_ids, T13.charge_item_ids,
T13.id AS payment_id, T13.id AS payment_id,
ai.picture_url AS picture_url, ai.picture_url AS picture_url,
T8.birth_date AS birth_date T8.birth_date AS birth_date,
T14.create_time AS return_date,
T14.return_reason AS return_reason,
T15.name AS operator_name,
T15.id AS operator_id,
T14.display_amount AS refund_amount,
T6.contract_no AS contract_no,
T16.refund_method AS refund_method
FROM adm_encounter AS T1 FROM adm_encounter AS T1
LEFT JOIN adm_organization AS T2 ON T1.organization_id = T2.ID AND T2.delete_flag = '0' LEFT JOIN adm_organization AS T2 ON T1.organization_id = T2.ID AND T2.delete_flag = '0'
LEFT JOIN adm_healthcare_service AS T3 ON T1.service_type_id = T3.ID AND T3.delete_flag = '0' LEFT JOIN adm_healthcare_service AS T3 ON T1.service_type_id = T3.ID AND T3.delete_flag = '0'

View File

@@ -4,35 +4,6 @@
<select id="getDiseaseTreatmentPage" parameterType="java.util.Map" <select id="getDiseaseTreatmentPage" parameterType="java.util.Map"
resultType="com.openhis.web.datadictionary.dto.DiagnosisTreatmentDto"> resultType="com.openhis.web.datadictionary.dto.DiagnosisTreatmentDto">
SELECT
T3.id,
T3.category_code,
T3.bus_no,
T3.name,
T3.py_str,
T3.wb_str,
T3.type_enum,
T3.permitted_unit_code,
T3.org_id,
T3.location_id,
T3.yb_flag,
T3.yb_no,
T3.yb_match_flag,
T3.status_enum,
T3.body_site_code,
T3.specimen_code,
T3.description_text,
T3.rule_id,
T3.tenant_id,
T3.item_type_code,
T3.yb_type,
T3.retail_price,
T3.maximum_retail_price,
T3.chrgitm_lv,--医保等级
T3.children_json,--子项json
T3.pricing_flag--划价标记
FROM
(
SELECT SELECT
T1.id, T1.id,
T1.category_code, T1.category_code,
@@ -57,24 +28,28 @@
T2.type_code as item_type_code, T2.type_code as item_type_code,
T2.yb_type, T2.yb_type,
T2.price as retail_price,--零售价 T2.price as retail_price,--零售价
( SELECT T4.amount T4.amount as maximum_retail_price,--最高零售价
FROM adm_charge_item_definition T5
LEFT JOIN adm_charge_item_def_detail T4 ON T4.definition_id = T5.id
WHERE T4.condition_code = '4'--4:限制
AND T5.instance_id = T1.id
AND T5.instance_table = 'wor_activity_definition'
) as maximum_retail_price,--最高零售价
T1.children_json,--子项json T1.children_json,--子项json
T1.pricing_flag--划价标记 T1.pricing_flag--划价标记
FROM wor_activity_definition T1 FROM wor_activity_definition T1
LEFT JOIN adm_charge_item_definition T2 ON T1.id = T2.instance_id LEFT JOIN adm_charge_item_definition T2 ON T1.id = T2.instance_id
LEFT JOIN adm_charge_item_definition T5 ON T5.instance_id = T1.id AND T5.instance_table = 'wor_activity_definition'
LEFT JOIN adm_charge_item_def_detail T4 ON T4.definition_id = T5.id AND T4.condition_code = '4'--4:限制
<where> <where>
T1.delete_flag = '0' T1.delete_flag = '0'
AND T2.instance_table = 'wor_activity_definition' AND T2.instance_table = 'wor_activity_definition'
<if test="ew.customSqlSegment != null and ew.customSqlSegment != ''">
<choose>
<when test="ew.customSqlSegment.contains('tenant_id')">
${ew.customSqlSegment.replaceFirst('tenant_id', 'T1.tenant_id').replaceFirst('WHERE', 'AND')}
</when>
<otherwise>
${ew.customSqlSegment.replaceFirst('WHERE', 'AND')}
</otherwise>
</choose>
</if>
</where> </where>
ORDER BY T1.bus_no DESC ORDER BY T1.bus_no DESC
) AS T3
${ew.customSqlSegment}
</select> </select>

View File

@@ -0,0 +1,96 @@
import Layout from '@/layout'
import router from './router'
import { ElMessage } from 'element-plus'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import { getToken } from '@/utils/auth'
import { isHttp } from '@/utils/validate'
import { isRelogin } from '@/utils/request'
import useUserStore from '@/store/modules/user'
import useSettingsStore from '@/store/modules/settings'
import usePermissionStore from '@/store/modules/permission'
NProgress.configure({ showSpinner: false });
const whiteList = ['/login', '/register'];
router.beforeEach((to, from, next) => {
NProgress.start()
if (getToken()) {
to.meta.title && useSettingsStore().setTitle(to.meta.title)
/* has token*/
if (to.path === '/login') {
next({ path: '/' })
NProgress.done()
} else if (whiteList.indexOf(to.path) !== -1) {
next()
} else {
if (useUserStore().roles.length === 0) {
isRelogin.show = true
// 判断当前用户是否已拉取完user_info信息
useUserStore().getInfo().then(() => {
isRelogin.show = false
usePermissionStore().generateRoutes().then(accessRoutes => {
// 根据roles权限生成可访问的路由表
accessRoutes.forEach(route => {
if (!isHttp(route.path)) {
// 检查是否已经存在同名路由
if (!router.hasRoute(route.name)) {
router.addRoute(route) // 动态添加可访问路由表
}
}
})
next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
})
}).catch(err => {
useUserStore().logOut().then(() => {
ElMessage.error(err)
next({ path: '/' })
})
})
} else {
next()
}
}
} else {
// 没有token
if (whiteList.indexOf(to.path) !== -1) {
// 在免登录白名单,直接进入
next()
} else {
next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页
NProgress.done()
}
}
})
router.afterEach(() => {
NProgress.done()
})
const appointmentRouter = {
path: '/appointment',
component: Layout,
redirect: '/appointment/manage',
name: 'Appointment',
meta: {
title: '预约管理',
icon: 'calendar'
},
children: [
{
path: 'manage',
component: () => import('@/views/appointment/manage'),
name: 'AppointmentManage', // 修改名称,避免与父级重复
meta: { title: '预约管理', icon: 'list' }
},
{
path: 'setting',
component: () => import('@/views/appointment/setting'),
name: 'AppointmentSetting',
meta: { title: '预约设置', icon: 'setting' }
}
]
}
export default appointmentRouter

View File

@@ -1,11 +0,0 @@
package com.openhis.administration.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.openhis.administration.domain.Dept;
import com.openhis.administration.mapper.DeptMapper;
import com.openhis.administration.service.IDeptService;
import org.springframework.stereotype.Service;
@Service
public class DeptImpl extends ServiceImpl<DeptMapper, Dept> implements IDeptService {
}

View File

@@ -1,14 +1,13 @@
package com.openhis.administration.domain; package com.openhis.appointmentmanage.domain;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List;
/** /**
* 科室Entity实体 * 科室Entity
* *
* @date 2025-12-08 * @date 2025-12-08
*/ */

View File

@@ -1,4 +1,4 @@
package com.openhis.administration.domain; package com.openhis.appointmentmanage.domain;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data; import lombok.Data;
@@ -6,7 +6,11 @@ import lombok.experimental.Accessors;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.LocalTime; import java.time.LocalTime;
/**
* 医生排班Entity
*
* @date 2025-12-12
*/
@Data @Data
@TableName(value = "adm_doctor_schedule") @TableName(value = "adm_doctor_schedule")
@Accessors(chain = true) @Accessors(chain = true)

View File

@@ -1,4 +1,4 @@
package com.openhis.administration.domain; package com.openhis.appointmentmanage.domain;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data; import lombok.Data;
@@ -7,7 +7,11 @@ import lombok.experimental.Accessors;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.LocalTime; import java.time.LocalTime;
/**
* 号源池Entity
*
* @date 2025-12-12
*/
@Data @Data
@TableName(value = "adm_schedule_pool") @TableName(value = "adm_schedule_pool")
@Accessors(chain = true) @Accessors(chain = true)
@@ -15,36 +19,84 @@ public class SchedulePool {
/** id */ /** id */
private Integer id; private Integer id;
/** 业务编号 */
private String poolCode; private String poolCode;
/** 医院ID */
private Integer hospitalId; private Integer hospitalId;
/** 科室ID */
private Integer deptId; private Integer deptId;
/** 医生ID */
private Integer doctorId; private Integer doctorId;
/** 医生姓名 */
private String doctorName; private String doctorName;
/** 诊室 */
private String clinicRoom; private String clinicRoom;
/** 出诊日期 */
private LocalDate scheduleDate; private LocalDate scheduleDate;
/** 班别 */
private String shift; private String shift;
/** 开始时间 */ /** 开始时间 */
private LocalTime startTime; private LocalTime startTime;
/** 结束时间 */ /** 结束时间 */
private LocalTime endTime; private LocalTime endTime;
/**/
/** 总号量 */
private Integer totalQuota; private Integer totalQuota;
/** 已约 */
private Integer bookedNum; private Integer bookedNum;
/** 铁号数 */
private Integer lockedNum; private Integer lockedNum;
/** 剩余号数 */
private Integer availableNum; private Integer availableNum;
/** 号别 */
private String regType; private String regType;
/** 原价 (元) */
private Double fee; private Double fee;
/** 医保限价 (元) */
private Double insurancePrice; private Double insurancePrice;
/** 支持渠道 */
private String supportChannel; private String supportChannel;
/** 号源状态 */
private Integer status; private Integer status;
/** 停诊原因 */
private String stopReason; private String stopReason;
/** 放号时间 */
private LocalDateTime releaseTime; private LocalDateTime releaseTime;
/** 截止预约时间 */
private LocalDateTime deadlineTime; private LocalDateTime deadlineTime;
/** 乐观锁版本 */
private Integer version; private Integer version;
/** 操作人ID */
private Integer opUserId; private Integer opUserId;
/** 备注 */
private String remark; private String remark;
/** 排班ID */
private Integer scheduleId; private Integer scheduleId;
/** 创建时间 */ /** 创建时间 */
private LocalDateTime createTime; private LocalDateTime createTime;

View File

@@ -1,4 +1,4 @@
package com.openhis.administration.domain; package com.openhis.appointmentmanage.domain;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data; import lombok.Data;
@@ -6,17 +6,33 @@ import lombok.experimental.Accessors;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.LocalTime; import java.time.LocalTime;
/**
* 号源池明细Entity
*
* @date 2025-12-12
*/
@Data @Data
@TableName(value = "adm_schedule_slot") @TableName(value = "adm_schedule_slot")
@Accessors(chain = true) @Accessors(chain = true)
public class ScheduleSlot { public class ScheduleSlot {
/** 明细主键 */
private Integer id; private Integer id;
/** 号源池ID */
private Integer poolId; private Integer poolId;
/** 序号 */
private Integer seqNo; private Integer seqNo;
/** 序号状态: 0-可用,1-已预约,2-已取消,3-已过期等 */
private Integer status; private Integer status;
/** 预约订单ID */
private Integer orderId; private Integer orderId;
/** 预计叫号时间 */
private LocalTime expectTime; private LocalTime expectTime;
/** 创建时间 */ /** 创建时间 */
private LocalDateTime createTime; private LocalDateTime createTime;

View File

@@ -1,7 +1,7 @@
package com.openhis.administration.mapper; package com.openhis.appointmentmanage.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.openhis.administration.domain.Dept; import com.openhis.appointmentmanage.domain.Dept;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
@Repository @Repository

View File

@@ -1,7 +1,7 @@
package com.openhis.administration.mapper; package com.openhis.appointmentmanage.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.openhis.administration.domain.DoctorSchedule; import com.openhis.appointmentmanage.domain.DoctorSchedule;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
@Repository @Repository

View File

@@ -1,7 +1,7 @@
package com.openhis.administration.mapper; package com.openhis.appointmentmanage.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.openhis.administration.domain.SchedulePool; import com.openhis.appointmentmanage.domain.SchedulePool;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
@Repository @Repository

View File

@@ -1,7 +1,7 @@
package com.openhis.administration.mapper; package com.openhis.appointmentmanage.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.openhis.administration.domain.ScheduleSlot; import com.openhis.appointmentmanage.domain.ScheduleSlot;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
@Repository @Repository

View File

@@ -1,7 +1,7 @@
package com.openhis.administration.service; package com.openhis.appointmentmanage.service;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import com.openhis.administration.domain.Dept; import com.openhis.appointmentmanage.domain.Dept;
public interface IDeptService extends IService<Dept> { public interface IDeptService extends IService<Dept> {
} }

View File

@@ -1,7 +1,7 @@
package com.openhis.administration.service; package com.openhis.appointmentmanage.service;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import com.openhis.administration.domain.DoctorSchedule; import com.openhis.appointmentmanage.domain.DoctorSchedule;
public interface IDoctorScheduleService extends IService<DoctorSchedule> { public interface IDoctorScheduleService extends IService<DoctorSchedule> {
} }

View File

@@ -1,7 +1,7 @@
package com.openhis.administration.service; package com.openhis.appointmentmanage.service;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import com.openhis.administration.domain.SchedulePool; import com.openhis.appointmentmanage.domain.SchedulePool;
public interface ISchedulePoolService extends IService<SchedulePool> { public interface ISchedulePoolService extends IService<SchedulePool> {
} }

View File

@@ -1,7 +1,7 @@
package com.openhis.administration.service; package com.openhis.appointmentmanage.service;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import com.openhis.administration.domain.ScheduleSlot; import com.openhis.appointmentmanage.domain.ScheduleSlot;
public interface IScheduleSlotService extends IService<ScheduleSlot> { public interface IScheduleSlotService extends IService<ScheduleSlot> {
} }

View File

@@ -0,0 +1,11 @@
package com.openhis.appointmentmanage.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.openhis.appointmentmanage.domain.Dept;
import com.openhis.appointmentmanage.mapper.DeptMapper;
import com.openhis.appointmentmanage.service.IDeptService;
import org.springframework.stereotype.Service;
@Service
public class DeptImpl extends ServiceImpl<DeptMapper, Dept> implements IDeptService {
}

View File

@@ -1,9 +1,9 @@
package com.openhis.administration.service.impl; package com.openhis.appointmentmanage.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.openhis.administration.domain.DoctorSchedule; import com.openhis.appointmentmanage.domain.DoctorSchedule;
import com.openhis.administration.mapper.DoctorScheduleMapper; import com.openhis.appointmentmanage.mapper.DoctorScheduleMapper;
import com.openhis.administration.service.IDoctorScheduleService; import com.openhis.appointmentmanage.service.IDoctorScheduleService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@Service @Service

View File

@@ -1,9 +1,9 @@
package com.openhis.administration.service.impl; package com.openhis.appointmentmanage.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.openhis.administration.domain.SchedulePool; import com.openhis.appointmentmanage.domain.SchedulePool;
import com.openhis.administration.mapper.SchedulePoolMapper; import com.openhis.appointmentmanage.mapper.SchedulePoolMapper;
import com.openhis.administration.service.ISchedulePoolService; import com.openhis.appointmentmanage.service.ISchedulePoolService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@Service @Service

View File

@@ -1,9 +1,9 @@
package com.openhis.administration.service.impl; package com.openhis.appointmentmanage.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.openhis.administration.domain.ScheduleSlot; import com.openhis.appointmentmanage.domain.ScheduleSlot;
import com.openhis.administration.mapper.ScheduleSlotMapper; import com.openhis.appointmentmanage.mapper.ScheduleSlotMapper;
import com.openhis.administration.service.IScheduleSlotService; import com.openhis.appointmentmanage.service.IScheduleSlotService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@Service @Service

File diff suppressed because it is too large Load Diff

View File

@@ -19,43 +19,43 @@
"url": "giturl" "url": "giturl"
}, },
"dependencies": { "dependencies": {
"@element-plus/icons-vue": "2.3.1", "@element-plus/icons-vue": "^2.3.2",
"@vueup/vue-quill": "1.2.0", "@vueup/vue-quill": "1.2.0",
"@vueuse/core": "10.6.1", "@vueuse/core": "^11.0.0",
"axios": "0.27.2", "axios": "^1.7.0",
"chart.js": "^4.5.1", "chart.js": "^4.5.1",
"d3": "^7.9.0", "d3": "^7.9.0",
"decimal.js": "^10.5.0", "decimal.js": "^10.5.0",
"echarts": "^5.4.3", "echarts": "^5.4.3",
"element-china-area-data": "^6.1.0", "element-china-area-data": "^6.1.0",
"element-plus": "2.9.11", "element-plus": "^2.12.0",
"file-saver": "2.0.5", "file-saver": "^2.0.5",
"fuse.js": "6.6.2", "fuse.js": "^7.0.0",
"html2pdf.js": "^0.10.3", "html2pdf.js": "^0.10.3",
"js-cookie": "3.0.5", "js-cookie": "^3.0.5",
"jsencrypt": "3.3.2", "jsencrypt": "^3.3.2",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"moment": "^2.30.1", "moment": "^2.30.1",
"nprogress": "0.2.0", "nprogress": "^0.2.0",
"pinia": "2.1.7", "pinia": "^2.2.0",
"pinyin": "^4.0.0-alpha.2", "pinyin": "^4.0.0-alpha.2",
"province-city-china": "^8.5.8", "province-city-china": "^8.5.8",
"segmentit": "^2.0.3", "segmentit": "^2.0.3",
"v-region": "^3.3.0", "v-region": "^3.3.0",
"vue": "^3.5.13", "vue": "^3.5.13",
"vue-area-linkage": "^5.1.0", "vue-area-linkage": "^5.1.0",
"vue-cropper": "1.1.1", "vue-cropper": "^1.1.1",
"vue-plugin-hiprint": "^0.0.60", "vue-plugin-hiprint": "^0.0.60",
"vue-router": "4.2.5" "vue-router": "^4.3.0"
}, },
"devDependencies": { "devDependencies": {
"@vitejs/plugin-vue": "4.5.0", "@vitejs/plugin-vue": "^5.0.0",
"@vue/compiler-sfc": "3.3.9", "@vue/compiler-sfc": "^3.5.25",
"sass": "1.69.5", "sass": "^1.77.8",
"unplugin-auto-import": "0.17.1", "unplugin-auto-import": "^0.19.0",
"unplugin-vue-setup-extend-plus": "1.0.0", "unplugin-vue-setup-extend-plus": "^1.0.0",
"vite": "^5.0.4", "vite": "^5.0.4",
"vite-plugin-compression": "0.5.1", "vite-plugin-compression": "^0.5.1",
"vite-plugin-svg-icons": "2.0.1" "vite-plugin-svg-icons": "^2.0.1"
} }
} }

View File

@@ -50,8 +50,10 @@ export function logout() {
// 获取验证码 // 获取验证码
export function getUserBindTenantList(username) { export function getUserBindTenantList(username) {
// 确保username存在避免构建出错误的URL
const safeUsername = username || '';
return request({ return request({
url: '/system/tenant/user-bind/'+username, url: '/system/tenant/user-bind/' + safeUsername,
headers: { headers: {
isToken: false isToken: false
}, },

View File

@@ -18,10 +18,11 @@ export function getConfig(configId) {
} }
// 根据参数键名查询参数值 // 根据参数键名查询参数值
export function getConfigKey(configKey) { export function getConfigKey(configKey, options = {}) {
return request({ return request({
url: '/system/config/configKey/' + configKey, url: '/system/config/configKey/' + configKey,
method: 'get' method: 'get',
...options
}) })
} }

View File

@@ -1,28 +1,16 @@
<template> <template>
<div class="editor-container">
<div> <div>
<el-upload <el-upload :action="uploadUrl" :before-upload="handleBeforeUpload" :on-success="handleUploadSuccess"
:action="uploadUrl" :on-error="handleUploadError" name="file" :show-file-list="false" :headers="headers" class="editor-img-uploader"
:before-upload="handleBeforeUpload" v-if="type == 'url'">
:on-success="handleUploadSuccess"
:on-error="handleUploadError"
name="file"
:show-file-list="false"
:headers="headers"
class="editor-img-uploader"
v-if="type == 'url'"
>
<i ref="uploadRef" class="editor-img-uploader"></i> <i ref="uploadRef" class="editor-img-uploader"></i>
</el-upload> </el-upload>
</div> </div>
<div class="editor"> <div class="editor">
<quill-editor <quill-editor ref="quillEditorRef" :content="content" @update:content="content = $event" contentType="html"
ref="quillEditorRef" @textChange="(e) => $emit('update:modelValue', content)" :options="options" :style="styles" />
v-model:content="content" </div>
contentType="html"
@textChange="(e) => $emit('update:modelValue', content)"
:options="options"
:style="styles"
/>
</div> </div>
</template> </template>
@@ -30,10 +18,11 @@
import { QuillEditor } from "@vueup/vue-quill"; import { QuillEditor } from "@vueup/vue-quill";
import "@vueup/vue-quill/dist/vue-quill.snow.css"; import "@vueup/vue-quill/dist/vue-quill.snow.css";
import { getToken } from "@/utils/auth"; import { getToken } from "@/utils/auth";
import { ref, computed, watch, onMounted } from 'vue';
const { proxy } = getCurrentInstance(); import modal from '@/plugins/modal';
const quillEditorRef = ref(); const quillEditorRef = ref();
const uploadRef = ref();
const uploadUrl = ref(import.meta.env.VITE_APP_BASE_API + "/common/upload"); // 上传的图片服务器地址 const uploadUrl = ref(import.meta.env.VITE_APP_BASE_API + "/common/upload"); // 上传的图片服务器地址
const headers = ref({ const headers = ref({
Authorization: "Bearer " + getToken() Authorization: "Bearer " + getToken()
@@ -115,32 +104,34 @@ watch(() => props.modelValue, (v) => {
// 如果设置了上传地址则自定义图片上传事件 // 如果设置了上传地址则自定义图片上传事件
onMounted(() => { onMounted(() => {
if (props.type == 'url') { if (props.type == 'url') {
let quill = quillEditorRef.value.getQuill(); let quill = quillEditorRef.value?.getQuill();
if (quill) {
let toolbar = quill.getModule("toolbar"); let toolbar = quill.getModule("toolbar");
toolbar.addHandler("image", (value) => { toolbar.addHandler("image", (value) => {
if (value) { if (value && uploadRef.value) {
proxy.$refs.uploadRef.click(); uploadRef.value.click();
} else { } else {
quill.format("image", false); quill.format("image", false);
} }
}); });
} }
}
}); });
// 上传前校检格式和大小 // 上传前校检格式和大小
function handleBeforeUpload(file) { function handleBeforeUpload(file) {
const type = ["image/jpeg", "image/jpg", "image/png", "image/svg"]; const type = ["image/jpeg", "image/jpg", "image/png", "image/svg+xml"];
const isJPG = type.includes(file.type); const isJPG = type.includes(file.type);
//检验文件格式 //检验文件格式
if (!isJPG) { if (!isJPG) {
proxy.$modal.msgError(`图片格式错误!`); modal.msgError(`图片格式错误!`);
return false; return false;
} }
// 校检文件大小 // 校检文件大小
if (props.fileSize) { if (props.fileSize) {
const isLt = file.size / 1024 / 1024 < props.fileSize; const isLt = file.size / 1024 / 1024 < props.fileSize;
if (!isLt) { if (!isLt) {
proxy.$modal.msgError(`上传文件大小不能超过 ${props.fileSize} MB!`); modal.msgError(`上传文件大小不能超过 ${props.fileSize} MB!`);
return false; return false;
} }
} }
@@ -152,21 +143,24 @@ function handleUploadSuccess(res, file) {
// 如果上传成功 // 如果上传成功
if (res.code == 200) { if (res.code == 200) {
// 获取富文本实例 // 获取富文本实例
let quill = toRaw(quillEditorRef.value).getQuill(); let quill = quillEditorRef.value?.getQuill();
if (quill) {
// 获取光标位置 // 获取光标位置
let length = quill.selection.savedRange.index; let range = quill.selection?.savedRange || quill.getSelection();
let length = range?.index || 0;
// 插入图片res.url为服务器返回的图片链接地址 // 插入图片res.url为服务器返回的图片链接地址
quill.insertEmbed(length, "image", import.meta.env.VITE_APP_BASE_API + res.fileName); quill.insertEmbed(length, "image", import.meta.env.VITE_APP_BASE_API + res.fileName);
// 调整光标到最后 // 调整光标到最后
quill.setSelection(length + 1); quill.setSelection(length + 1);
}
} else { } else {
proxy.$modal.msgError("图片插入失败"); modal.msgError("图片插入失败");
} }
} }
// 上传失败处理 // 上传失败处理
function handleUploadError() { function handleUploadError() {
proxy.$modal.msgError("图片插入失败"); modal.msgError("图片插入失败");
} }
</script> </script>
@@ -174,76 +168,96 @@ function handleUploadError() {
.editor-img-uploader { .editor-img-uploader {
display: none; display: none;
} }
.editor, .ql-toolbar {
.editor,
.ql-toolbar {
white-space: pre-wrap !important; white-space: pre-wrap !important;
line-height: normal !important; line-height: normal !important;
} }
.quill-img { .quill-img {
display: none; display: none;
} }
.ql-snow .ql-tooltip[data-mode="link"]::before { .ql-snow .ql-tooltip[data-mode="link"]::before {
content: "请输入链接地址:"; content: "请输入链接地址:";
} }
.ql-snow .ql-tooltip.ql-editing a.ql-action::after { .ql-snow .ql-tooltip.ql-editing a.ql-action::after {
border-right: 0px; border-right: 0px;
content: "保存"; content: "保存";
padding-right: 0px; padding-right: 0px;
} }
.ql-snow .ql-tooltip[data-mode="video"]::before { .ql-snow .ql-tooltip[data-mode="video"]::before {
content: "请输入视频地址:"; content: "请输入视频地址:";
} }
.ql-snow .ql-picker.ql-size .ql-picker-label::before, .ql-snow .ql-picker.ql-size .ql-picker-label::before,
.ql-snow .ql-picker.ql-size .ql-picker-item::before { .ql-snow .ql-picker.ql-size .ql-picker-item::before {
content: "14px"; content: "14px";
} }
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before, .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before { .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {
content: "10px"; content: "10px";
} }
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before, .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before { .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {
content: "18px"; content: "18px";
} }
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before, .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before { .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {
content: "32px"; content: "32px";
} }
.ql-snow .ql-picker.ql-header .ql-picker-label::before, .ql-snow .ql-picker.ql-header .ql-picker-label::before,
.ql-snow .ql-picker.ql-header .ql-picker-item::before { .ql-snow .ql-picker.ql-header .ql-picker-item::before {
content: "文本"; content: "文本";
} }
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before, .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before { .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
content: "标题1"; content: "标题1";
} }
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before, .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before { .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
content: "标题2"; content: "标题2";
} }
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before, .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before { .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
content: "标题3"; content: "标题3";
} }
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before, .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before { .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
content: "标题4"; content: "标题4";
} }
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before, .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before { .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
content: "标题5"; content: "标题5";
} }
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before, .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before { .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
content: "标题6"; content: "标题6";
} }
.ql-snow .ql-picker.ql-font .ql-picker-label::before, .ql-snow .ql-picker.ql-font .ql-picker-label::before,
.ql-snow .ql-picker.ql-font .ql-picker-item::before { .ql-snow .ql-picker.ql-font .ql-picker-item::before {
content: "标准字体"; content: "标准字体";
} }
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before, .ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before { .ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before {
content: "衬线字体"; content: "衬线字体";
} }
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before, .ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before { .ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before {
content: "等宽字体"; content: "等宽字体";

View File

@@ -39,7 +39,9 @@
</template> </template>
<script setup> <script setup>
import { ref, computed, watch } from 'vue';
import { getToken } from "@/utils/auth"; import { getToken } from "@/utils/auth";
import modal from '@/plugins/modal';
const props = defineProps({ const props = defineProps({
modelValue: [String, Object, Array], modelValue: [String, Object, Array],
@@ -65,7 +67,7 @@ const props = defineProps({
} }
}); });
const { proxy } = getCurrentInstance(); const fileUpload = ref(null);
const emit = defineEmits(); const emit = defineEmits();
const number = ref(0); const number = ref(0);
const uploadList = ref([]); const uploadList = ref([]);
@@ -104,7 +106,7 @@ function handleBeforeUpload(file) {
const fileExt = fileName[fileName.length - 1]; const fileExt = fileName[fileName.length - 1];
const isTypeOk = props.fileType.indexOf(fileExt) >= 0; const isTypeOk = props.fileType.indexOf(fileExt) >= 0;
if (!isTypeOk) { if (!isTypeOk) {
proxy.$modal.msgError(`文件格式不正确, 请上传${props.fileType.join("/")}格式文件!`); modal.msgError(`文件格式不正确, 请上传${props.fileType.join("/")}格式文件!`);
return false; return false;
} }
} }
@@ -112,23 +114,23 @@ function handleBeforeUpload(file) {
if (props.fileSize) { if (props.fileSize) {
const isLt = file.size / 1024 / 1024 < props.fileSize; const isLt = file.size / 1024 / 1024 < props.fileSize;
if (!isLt) { if (!isLt) {
proxy.$modal.msgError(`上传文件大小不能超过 ${props.fileSize} MB!`); modal.msgError(`上传文件大小不能超过 ${props.fileSize} MB!`);
return false; return false;
} }
} }
proxy.$modal.loading("正在上传文件,请稍候..."); modal.loading("正在上传文件,请稍候...");
number.value++; number.value++;
return true; return true;
} }
// 文件个数超出 // 文件个数超出
function handleExceed() { function handleExceed() {
proxy.$modal.msgError(`上传文件数量不能超过 ${props.limit} 个!`); modal.msgError(`上传文件数量不能超过 ${props.limit} 个!`);
} }
// 上传失败 // 上传失败
function handleUploadError(err) { function handleUploadError(err) {
proxy.$modal.msgError("上传文件失败"); modal.msgError("上传文件失败");
} }
// 上传成功回调 // 上传成功回调
@@ -138,9 +140,9 @@ function handleUploadSuccess(res, file) {
uploadedSuccessfully(); uploadedSuccessfully();
} else { } else {
number.value--; number.value--;
proxy.$modal.closeLoading(); modal.closeLoading();
proxy.$modal.msgError(res.msg); modal.msgError(res.msg);
proxy.$refs.fileUpload.handleRemove(file); fileUpload.value.handleRemove(file);
uploadedSuccessfully(); uploadedSuccessfully();
} }
} }
@@ -158,7 +160,7 @@ function uploadedSuccessfully() {
uploadList.value = []; uploadList.value = [];
number.value = 0; number.value = 0;
emit("update:modelValue", listToString(fileList.value)); emit("update:modelValue", listToString(fileList.value));
proxy.$modal.closeLoading(); modal.closeLoading();
} }
} }

View File

@@ -47,6 +47,8 @@
<script setup> <script setup>
import { getToken } from "@/utils/auth"; import { getToken } from "@/utils/auth";
import { ref, computed, watch, getCurrentInstance } from 'vue';
import modal from '@/plugins/modal';
const props = defineProps({ const props = defineProps({
modelValue: [String, Object, Array], modelValue: [String, Object, Array],
@@ -72,7 +74,6 @@ const props = defineProps({
}, },
}); });
const { proxy } = getCurrentInstance();
const emit = defineEmits(); const emit = defineEmits();
const number = ref(0); const number = ref(0);
const uploadList = ref([]); const uploadList = ref([]);
@@ -82,6 +83,7 @@ const baseUrl = import.meta.env.VITE_APP_BASE_API;
const uploadImgUrl = ref(import.meta.env.VITE_APP_BASE_API + "/common/upload"); // 上传的图片服务器地址 const uploadImgUrl = ref(import.meta.env.VITE_APP_BASE_API + "/common/upload"); // 上传的图片服务器地址
const headers = ref({ Authorization: "Bearer " + getToken() }); const headers = ref({ Authorization: "Bearer " + getToken() });
const fileList = ref([]); const fileList = ref([]);
const imageUpload = ref(null);
const showTip = computed( const showTip = computed(
() => props.isShowTip && (props.fileType || props.fileSize) () => props.isShowTip && (props.fileType || props.fileSize)
); );
@@ -124,7 +126,7 @@ function handleBeforeUpload(file) {
isImg = file.type.indexOf("image") > -1; isImg = file.type.indexOf("image") > -1;
} }
if (!isImg) { if (!isImg) {
proxy.$modal.msgError( modal.msgError(
`文件格式不正确, 请上传${props.fileType.join("/")}图片格式文件!` `文件格式不正确, 请上传${props.fileType.join("/")}图片格式文件!`
); );
return false; return false;
@@ -132,17 +134,17 @@ function handleBeforeUpload(file) {
if (props.fileSize) { if (props.fileSize) {
const isLt = file.size / 1024 / 1024 < props.fileSize; const isLt = file.size / 1024 / 1024 < props.fileSize;
if (!isLt) { if (!isLt) {
proxy.$modal.msgError(`上传头像图片大小不能超过 ${props.fileSize} MB!`); modal.msgError(`上传头像图片大小不能超过 ${props.fileSize} MB!`);
return false; return false;
} }
} }
proxy.$modal.loading("正在上传图片,请稍候..."); modal.loading("正在上传图片,请稍候...");
number.value++; number.value++;
} }
// 文件个数超出 // 文件个数超出
function handleExceed() { function handleExceed() {
proxy.$modal.msgError(`上传文件数量不能超过 ${props.limit} 个!`); modal.msgError(`上传文件数量不能超过 ${props.limit} 个!`);
} }
// 上传成功回调 // 上传成功回调
@@ -152,9 +154,9 @@ function handleUploadSuccess(res, file) {
uploadedSuccessfully(); uploadedSuccessfully();
} else { } else {
number.value--; number.value--;
proxy.$modal.closeLoading(); modal.closeLoading();
proxy.$modal.msgError(res.msg); modal.msgError(res.msg);
proxy.$refs.imageUpload.handleRemove(file); imageUpload.value.handleRemove(file);
uploadedSuccessfully(); uploadedSuccessfully();
} }
} }
@@ -176,14 +178,14 @@ function uploadedSuccessfully() {
uploadList.value = []; uploadList.value = [];
number.value = 0; number.value = 0;
emit("update:modelValue", listToString(fileList.value)); emit("update:modelValue", listToString(fileList.value));
proxy.$modal.closeLoading(); modal.closeLoading();
} }
} }
// 上传失败 // 上传失败
function handleUploadError() { function handleUploadError() {
proxy.$modal.msgError("上传图片失败"); modal.msgError("上传图片失败");
proxy.$modal.closeLoading(); modal.closeLoading();
} }
// 预览 // 预览

View File

@@ -29,8 +29,11 @@
</template> </template>
<script setup> <script setup>
import { ref, computed, watch, onMounted, nextTick } from 'vue';
import { getCurrentInstance } from 'vue';
const { proxy } = getCurrentInstance(); const selectTree = ref(null);
const treeSelect = ref(null);
const props = defineProps({ const props = defineProps({
/* 配置项 */ /* 配置项 */
@@ -83,10 +86,10 @@ function initHandle() {
nextTick(() => { nextTick(() => {
const selectedValue = valueId.value; const selectedValue = valueId.value;
if(selectedValue !== null && typeof (selectedValue) !== 'undefined') { if(selectedValue !== null && typeof (selectedValue) !== 'undefined') {
const node = proxy.$refs.selectTree.getNode(selectedValue) const node = selectTree.value.getNode(selectedValue)
if (node) { if (node) {
valueTitle.value = node.data[props.objMap.label] valueTitle.value = node.data[props.objMap.label]
proxy.$refs.selectTree.setCurrentKey(selectedValue) // 设置默认选中 selectTree.value.setCurrentKey(selectedValue) // 设置默认选中
defaultExpandedKey.value = [selectedValue] // 设置默认展开 defaultExpandedKey.value = [selectedValue] // 设置默认展开
} }
} else { } else {
@@ -98,11 +101,11 @@ function handleNodeClick(node) {
valueTitle.value = node[props.objMap.label] valueTitle.value = node[props.objMap.label]
valueId.value = node[props.objMap.value]; valueId.value = node[props.objMap.value];
defaultExpandedKey.value = []; defaultExpandedKey.value = [];
proxy.$refs.treeSelect.blur() treeSelect.value.blur()
selectFilterData('') selectFilterData('')
} }
function selectFilterData(val) { function selectFilterData(val) {
proxy.$refs.selectTree.filter(val) selectTree.value.filter(val)
} }
function filterNode(value, data) { function filterNode(value, data) {
if (!value) return true if (!value) return true

View File

@@ -85,6 +85,14 @@ function resolvePath(routePath, routeQuery) {
if (isExternal(props.basePath)) { if (isExternal(props.basePath)) {
return props.basePath return props.basePath
} }
// 特殊处理门诊医生站路径,确保路径正确
if (routePath === '/doctorstation' || routePath === 'doctorstation') {
if (routeQuery) {
let query = JSON.parse(routeQuery);
return { path: '/doctorstation', query: query }
}
return '/doctorstation'
}
if (routeQuery) { if (routeQuery) {
let query = JSON.parse(routeQuery); let query = JSON.parse(routeQuery);
return { path: getNormalPath(props.basePath + '/' + routePath), query: query } return { path: getNormalPath(props.basePath + '/' + routePath), query: query }

View File

@@ -1,11 +1,30 @@
import { createApp } from 'vue' import { createApp } from 'vue'
// 修复 util._extend 已弃用警告(仅在 Node.js 环境中需要)
if (typeof process !== 'undefined' && process.versions && process.versions.node) {
try {
import('util').then(util => {
if (!util._extend) {
util._extend = function(destination, source) {
for (var key in source) {
if (source.hasOwnProperty(key)) {
destination[key] = source[key];
}
}
return destination;
};
}
});
} catch (e) {
console.error('util._extend 补丁加载失败:', e);
}
}
import Cookies from 'js-cookie' import Cookies from 'js-cookie'
import ElementPlus from 'element-plus' import ElementPlus from 'element-plus'
import zhCn from 'element-plus/es/locale/lang/zh-cn' import zhCn from 'element-plus/es/locale/lang/zh-cn'
import 'element-plus/dist/index.css' import 'element-plus/dist/index.css'
import locale from 'element-plus/es/locale/lang/zh-cn'
import '@/assets/styles/index.scss' // global css import '@/assets/styles/index.scss' // global css
@@ -84,8 +103,14 @@ app.component('ImageUpload', ImageUpload)
app.component('ImagePreview', ImagePreview) app.component('ImagePreview', ImagePreview)
app.component('RightToolbar', RightToolbar) app.component('RightToolbar', RightToolbar)
app.component('Editor', Editor) app.component('Editor', Editor)
app.use(registerComponents) // 使用element-plus 并且设置全局的大小
app.use(ElementPlus, {
locale: zhCn,
// 支持 large、default、small
size: Cookies.get('size') || 'default'
})
app.use(ElMessage) app.use(ElMessage)
app.use(registerComponents)
app.use(router) app.use(router)
app.use(store) app.use(store)
app.use(plugins) app.use(plugins)
@@ -94,11 +119,5 @@ app.component('svg-icon', SvgIcon)
directive(app) directive(app)
// 全局禁止点击遮罩层关闭弹窗 // 全局禁止点击遮罩层关闭弹窗
ElDialog.props.closeOnClickModal.default = false; ElDialog.props.closeOnClickModal.default = false;
// 使用element-plus 并且设置全局的大小
app.use(ElementPlus, {
locale: zhCn,
// 支持 large、default、small
size: Cookies.get('size') || 'default'
})
app.mount('#app') app.mount('#app')

View File

@@ -33,8 +33,11 @@ router.beforeEach((to, from, next) => {
// 根据roles权限生成可访问的路由表 // 根据roles权限生成可访问的路由表
accessRoutes.forEach(route => { accessRoutes.forEach(route => {
if (!isHttp(route.path)) { if (!isHttp(route.path)) {
// 检查是否已经存在同名路由
if (!router.hasRoute(route.name)) {
router.addRoute(route) // 动态添加可访问路由表 router.addRoute(route) // 动态添加可访问路由表
} }
}
}) })
next({ ...to, replace: true }) // hack方法 确保addRoutes已完成 next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
}) })

View File

@@ -3,30 +3,45 @@ import { createWebHistory, createRouter } from 'vue-router'
import Layout from '@/layout' import Layout from '@/layout'
/** /**
* Note: 路由配置项 * Note: 路由配置项说明
* *
* hidden: true // 当设置 true 的时候该路由不会侧边栏出现 如401login等页面者如一些编辑页面/edit/1 * hidden: true // 当设置 true 时,该路由不会侧边栏出现如401login等页面或一些编辑页面/edit/1
* alwaysShow: true // 当你一个路由下的 children 声明的路由大于1个时自动会变成嵌套模式--如组件页面 * alwaysShow: true // 当路由下的 children 声明的路由大于1个时自动变为嵌套模式如组件页面
* // 只有一个时,会将那个子路由当做根路由显示在侧边栏--如引导页面 * // 只有一个时,会将子路由作为根路由显示在侧边栏如引导页面
* // 若想不管路由下面的 children 声明的个数都显示你的根路由 * // 若想不管 children 个数都显示根路由,可设置 alwaysShow: true忽略之前定义的规则
* // 你可以设置 alwaysShow: true这样它就会忽略之前定义的规则一直显示根路由 * redirect: noRedirect // 当设置 noRedirect 时,该路由在面包屑导航中不可点击
* redirect: noRedirect // 当设置 noRedirect 的时候该路由在面包屑导航中不可被点击 * name:'router-name' // 设定路由的名字,必须填写,否则使用<keep-alive>时会出现问题
* name:'router-name' // 设定路由的名字,一定要填写不然使用<keep-alive>时会出现各种问题
* query: '{"id": 1, "name": "ry"}' // 访问路由的默认传递参数 * query: '{"id": 1, "name": "ry"}' // 访问路由的默认传递参数
* roles: ['admin', 'common'] // 访问路由的角色权限 * roles: ['admin', 'common'] // 访问路由的角色权限
* permissions: ['a:a:a', 'b:b:b'] // 访问路由的菜单权限 * permissions: ['a:a:a', 'b:b:b'] // 访问路由的菜单权限
* meta : { * meta: {
noCache: true // 如果设置为true则不会被 <keep-alive> 缓存(默认 false) noCache: true // 如果设置为true则不会被 <keep-alive> 缓存默认 false
title: 'title' // 设置该路由在侧边栏和面包屑中展示的名字 title: 'title' // 设置该路由在侧边栏和面包屑中展示的名字
icon: 'svg-name' // 设置该路由的图标对应路径src/assets/icons/svg icon: 'svg-name' // 设置该路由的图标对应路径src/assets/icons/svg
breadcrumb: false // 如果设置为false则不会在breadcrumb面包屑中显示 breadcrumb: false // 如果设置为false则不会在breadcrumb面包屑中显示
activeMenu: '/system/user' // 当路由设置了该属性,则会高亮对应的侧边栏 activeMenu: '/system/user' // 当路由设置了该属性,则会高亮对应的侧边栏
} }
*/ */
// 公共路由 // 公共路由 - 所有用户均可访问的路由
export const constantRoutes = [ export const constantRoutes = [
{ path: '/appoinmentmanage', component: Layout, redirect: '/appoinmentmanage', name: 'AppoinmentManage', hidden: true, meta: { title: '预约管理', icon: 'component' }, children: [{ path: '', component: () => import('@/views/appoinmentmanage/index.vue'), name: 'AppoinmentManageIndex', meta: { title: '预约管理' } }, { path: 'doctorschedule/:deptId', component: () => import('@/views/appoinmentmanage/doctorschedule/index.vue'), name: 'DoctorSchedule', hidden: true, meta: { title: '医生排班' } }] }, // 门诊医生站路由
{
path: '/doctorstation',
component: Layout,
redirect: '/doctorstation',
name: 'DoctorStation',
meta: { title: '门诊医生站', icon: 'doctorstation' },
children: [
{
path: '',
component: () => import('@/views/doctorstation/index.vue'),
name: 'DoctorStationIndex',
meta: { title: '门诊医生站', icon: 'doctorstation' }
}
]
},
// 重定向路由
{ {
path: '/redirect', path: '/redirect',
component: Layout, component: Layout,
@@ -38,21 +53,25 @@ export const constantRoutes = [
} }
] ]
}, },
// 登录路由
{ {
path: '/login', path: '/login',
component: () => import('@/views/login'), component: () => import('@/views/login'),
hidden: true hidden: true
}, },
// 注册路由
{ {
path: '/register', path: '/register',
component: () => import('@/views/register'), component: () => import('@/views/register'),
hidden: true hidden: true
}, },
// 401权限不足路由
{ {
path: '/401', path: '/401',
component: () => import('@/views/error/401'), component: () => import('@/views/error/401'),
hidden: true hidden: true
}, },
// 首页路由
{ {
path: '', path: '',
component: Layout, component: Layout,
@@ -66,6 +85,7 @@ export const constantRoutes = [
} }
] ]
}, },
// 个人中心路由
{ {
path: '/user', path: '/user',
component: Layout, component: Layout,
@@ -80,7 +100,7 @@ export const constantRoutes = [
} }
] ]
}, },
// 添加套餐管理相关路由到公共路由确保始终可用 // 套餐管理相关路由 - 添加到公共路由确保始终可用
{ {
path: '/maintainSystem/Inspection/PackageManagement', path: '/maintainSystem/Inspection/PackageManagement',
component: Layout, component: Layout,
@@ -93,11 +113,26 @@ export const constantRoutes = [
meta: { title: '套餐管理' } meta: { title: '套餐管理' }
} }
] ]
},
// 预约管理直接访问路由 - 兼容外部系统访问
{
path: '/reservationRecord2/appoinmentmanage',
component: Layout,
hidden: true,
children: [
{
path: '',
component: () => import('@/views/appoinmentmanage/clinicRoom/index.vue'),
name: 'DirectClinicRoom',
meta: { title: '门诊出诊医生诊室设置' }
}
]
} }
] ]
// 动态路由基于用户权限动态加载 // 动态路由 - 基于用户权限动态加载的路由
export const dynamicRoutes = [ export const dynamicRoutes = [
// 基础管理路由
{ {
path: '/basicmanage', path: '/basicmanage',
component: Layout, component: Layout,
@@ -113,7 +148,7 @@ export const dynamicRoutes = [
} }
] ]
}, },
// 兼容系统业务管理路径 // 兼容系统业务管理路径的发票管理路由
{ {
path: '/system/ywgz', path: '/system/ywgz',
component: Layout, component: Layout,
@@ -128,6 +163,7 @@ export const dynamicRoutes = [
} }
] ]
}, },
// 维护系统路由
{ {
path: '/maintainSystem', path: '/maintainSystem',
component: Layout, component: Layout,
@@ -137,22 +173,23 @@ export const dynamicRoutes = [
children: [ children: [
{ {
path: '', path: '',
redirect: 'chargeConfig' redirect: 'chargeConfig',
name: 'MaintainSystemIndex' // 添加名称以解决警告
}, },
{ {
path: 'chargeConfig', path: 'chargeConfig', // 收费配置路由
component: () => import('@/views/maintainSystem/chargeConfig/index.vue'), component: () => import('@/views/maintainSystem/chargeConfig/index.vue'),
name: 'ChargeConfig', name: 'ChargeConfig',
meta: { title: '挂号收费系统参数维护', icon: 'config', permissions: ['maintainSystem:chargeConfig:list'] } meta: { title: '挂号收费系统参数维护', icon: 'config', permissions: ['maintainSystem:chargeConfig:list'] }
}, },
{ {
path: 'Inspection', path: 'Inspection', // 检验管理路由
component: () => import('@/views/maintainSystem/Inspection/index.vue'), component: () => import('@/views/maintainSystem/Inspection/index.vue'),
name: 'Inspection', name: 'Inspection',
meta: { title: '检验管理', icon: 'inspection' }, meta: { title: '检验管理', icon: 'inspection' },
children: [ children: [
{ {
path: 'PackageManagement', path: 'PackageManagement', // 套餐管理路由
component: () => import('@/views/maintainSystem/Inspection/PackageManagement.vue'), component: () => import('@/views/maintainSystem/Inspection/PackageManagement.vue'),
name: 'PackageManagement', name: 'PackageManagement',
meta: { title: '套餐管理' } meta: { title: '套餐管理' }
@@ -161,6 +198,7 @@ export const dynamicRoutes = [
} }
] ]
}, },
// 系统管理路由
{ {
path: '/system', path: '/system',
component: Layout, component: Layout,
@@ -169,61 +207,62 @@ export const dynamicRoutes = [
meta: { title: '系统管理', icon: 'system' }, meta: { title: '系统管理', icon: 'system' },
children: [ children: [
{ {
path: 'user', path: 'user', // 用户管理路由
component: () => import('@/views/system/user/index.vue'), component: () => import('@/views/system/user/index.vue'),
name: 'User', name: 'User',
meta: { title: '用户管理', icon: 'user', permissions: ['system:user:list'] } meta: { title: '用户管理', icon: 'user', permissions: ['system:user:list'] }
}, },
{ {
path: 'role', path: 'role', // 角色管理路由
component: () => import('@/views/system/role/index.vue'), component: () => import('@/views/system/role/index.vue'),
name: 'Role', name: 'Role',
meta: { title: '角色管理', icon: 'role', permissions: ['system:role:list'] } meta: { title: '角色管理', icon: 'role', permissions: ['system:role:list'] }
}, },
{ {
path: 'menu', path: 'menu', // 菜单管理路由
component: () => import('@/views/system/menu/index.vue'), component: () => import('@/views/system/menu/index.vue'),
name: 'Menu', name: 'Menu',
meta: { title: '菜单管理', icon: 'menu', permissions: ['system:menu:list'] } meta: { title: '菜单管理', icon: 'menu', permissions: ['system:menu:list'] }
}, },
{ {
path: 'dept', path: 'dept', // 部门管理路由
component: () => import('@/views/system/dept/index.vue'), component: () => import('@/views/system/dept/index.vue'),
name: 'Dept', name: 'Dept',
meta: { title: '部门管理', icon: 'dept', permissions: ['system:dept:list'] } meta: { title: '部门管理', icon: 'dept', permissions: ['system:dept:list'] }
}, },
{ {
path: 'post', path: 'post', // 岗位管理路由
component: () => import('@/views/system/post/index.vue'), component: () => import('@/views/system/post/index.vue'),
name: 'Post', name: 'Post',
meta: { title: '岗位管理', icon: 'post', permissions: ['system:post:list'] } meta: { title: '岗位管理', icon: 'post', permissions: ['system:post:list'] }
}, },
{ {
path: 'dict', path: 'dict', // 字典管理路由
component: () => import('@/views/system/dict/index.vue'), component: () => import('@/views/system/dict/index.vue'),
name: 'Dict', name: 'Dict',
meta: { title: '字典管理', icon: 'dict', permissions: ['system:dict:list'] } meta: { title: '字典管理', icon: 'dict', permissions: ['system:dict:list'] }
}, },
{ {
path: 'config', path: 'config', // 参数配置路由
component: () => import('@/views/system/config/index.vue'), component: () => import('@/views/system/config/index.vue'),
name: 'Config', name: 'Config',
meta: { title: '参数配置', icon: 'config', permissions: ['system:config:list'] } meta: { title: '参数配置', icon: 'config', permissions: ['system:config:list'] }
}, },
{ {
path: 'notice', path: 'notice', // 通知公告路由
component: () => import('@/views/system/notice/index.vue'), component: () => import('@/views/system/notice/index.vue'),
name: 'Notice', name: 'Notice',
meta: { title: '通知公告', icon: 'notice', permissions: ['system:notice:list'] } meta: { title: '通知公告', icon: 'notice', permissions: ['system:notice:list'] }
}, },
{ {
path: 'tenant', path: 'tenant', // 租户管理路由
component: () => import('@/views/system/tenant/index.vue'), component: () => import('@/views/system/tenant/index.vue'),
name: 'Tenant', name: 'Tenant',
meta: { title: '租户管理', icon: 'tenant', permissions: ['system:tenant:list'] } meta: { title: '租户管理', icon: 'tenant', permissions: ['system:tenant:list'] }
} }
] ]
}, },
// 租户用户设置路由
{ {
path: '/system/tenant-user', path: '/system/tenant-user',
component: Layout, component: Layout,
@@ -238,6 +277,7 @@ export const dynamicRoutes = [
} }
] ]
}, },
// 租户合同管理路由
{ {
path: '/system/tenant-contract', path: '/system/tenant-contract',
component: Layout, component: Layout,
@@ -252,6 +292,7 @@ export const dynamicRoutes = [
} }
] ]
}, },
// 用户角色分配路由
{ {
path: '/system/user-auth', path: '/system/user-auth',
component: Layout, component: Layout,
@@ -266,6 +307,7 @@ export const dynamicRoutes = [
} }
] ]
}, },
// 角色用户分配路由
{ {
path: '/system/role-auth', path: '/system/role-auth',
component: Layout, component: Layout,
@@ -280,6 +322,7 @@ export const dynamicRoutes = [
} }
] ]
}, },
// 字典数据路由
{ {
path: '/system/dict-data', path: '/system/dict-data',
component: Layout, component: Layout,
@@ -294,6 +337,7 @@ export const dynamicRoutes = [
} }
] ]
}, },
// 系统监控路由
{ {
path: '/monitor', path: '/monitor',
component: Layout, component: Layout,
@@ -302,25 +346,26 @@ export const dynamicRoutes = [
meta: { title: '系统监控', icon: 'monitor' }, meta: { title: '系统监控', icon: 'monitor' },
children: [ children: [
{ {
path: 'operlog', path: 'operlog', // 操作日志路由
component: () => import('@/views/monitor/operlog/index.vue'), component: () => import('@/views/monitor/operlog/index.vue'),
name: 'Operlog', name: 'Operlog',
meta: { title: '操作日志', icon: 'operlog', permissions: ['monitor:operlog:list'] } meta: { title: '操作日志', icon: 'operlog', permissions: ['monitor:operlog:list'] }
}, },
{ {
path: 'logininfor', path: 'logininfor', // 登录日志路由
component: () => import('@/views/monitor/logininfor/index.vue'), component: () => import('@/views/monitor/logininfor/index.vue'),
name: 'Logininfor', name: 'Logininfor',
meta: { title: '登录日志', icon: 'logininfor', permissions: ['monitor:logininfor:list'] } meta: { title: '登录日志', icon: 'logininfor', permissions: ['monitor:logininfor:list'] }
}, },
{ {
path: 'job', path: 'job', // 定时任务路由
component: () => import('@/views/monitor/job/index.vue'), component: () => import('@/views/monitor/job/index.vue'),
name: 'Job', name: 'Job',
meta: { title: '定时任务', icon: 'job', permissions: ['monitor:job:list'] } meta: { title: '定时任务', icon: 'job', permissions: ['monitor:job:list'] }
} }
] ]
}, },
// 系统工具路由
{ {
path: '/tool', path: '/tool',
component: Layout, component: Layout,
@@ -329,13 +374,14 @@ export const dynamicRoutes = [
meta: { title: '系统工具', icon: 'tool' }, meta: { title: '系统工具', icon: 'tool' },
children: [ children: [
{ {
path: 'gen', path: 'gen', // 代码生成路由
component: () => import('@/views/tool/gen/index.vue'), component: () => import('@/views/tool/gen/index.vue'),
name: 'Gen', name: 'Gen',
meta: { title: '代码生成', icon: 'gen', permissions: ['tool:gen:list'] } meta: { title: '代码生成', icon: 'gen', permissions: ['tool:gen:list'] }
} }
] ]
}, },
// 定时任务日志路由
{ {
path: '/monitor/job-log', path: '/monitor/job-log',
component: Layout, component: Layout,
@@ -350,6 +396,7 @@ export const dynamicRoutes = [
} }
] ]
}, },
// 代码生成编辑路由
{ {
path: '/tool/gen-edit', path: '/tool/gen-edit',
component: Layout, component: Layout,
@@ -369,17 +416,19 @@ export const dynamicRoutes = [
// 合并常量路由和动态路由,确保所有路由都能被访问 // 合并常量路由和动态路由,确保所有路由都能被访问
const allRoutes = [...constantRoutes, ...dynamicRoutes]; const allRoutes = [...constantRoutes, ...dynamicRoutes];
// 添加404路由到所有路由的最后 // 添加404路由到所有路由的最后,确保捕获所有未匹配的路由
allRoutes.push({ allRoutes.push({
path: "/:pathMatch(.*)*", path: "/:pathMatch(.*)*",
component: () => import('@/views/error/404'), component: () => import('@/views/error/404'),
hidden: true hidden: true
}); });
// 创建Vue Router实例
const router = createRouter({ const router = createRouter({
history: createWebHistory(), history: createWebHistory(), // 使用HTML5历史模式
routes: allRoutes, routes: allRoutes, // 使用合并后的所有路由
scrollBehavior(to, from, savedPosition) { scrollBehavior(to, from, savedPosition) {
// 页面滚动行为:如果有保存的位置则恢复,否则滚动到顶部
if (savedPosition) { if (savedPosition) {
return savedPosition return savedPosition
} else { } else {
@@ -388,4 +437,5 @@ const router = createRouter({
}, },
}); });
// 导出路由实例
export default router; export default router;

View File

@@ -1,6 +1,8 @@
<template> <template>
<!-- 跌倒/坠床评估护理记录单主容器 -->
<div> <div>
<div class="business"> <div class="business">
<!-- 已有记录展示表格 -->
<el-table <el-table
:data="tableDataSource" :data="tableDataSource"
border border
@@ -8,10 +10,15 @@
fit fit
:header-cell-style="{ background: '#f2f2f2', color: 'black' }" :header-cell-style="{ background: '#f2f2f2', color: 'black' }"
> >
<!-- 记录时间列 -->
<el-table-column prop="content.recordTime" label="记录时间" /> <el-table-column prop="content.recordTime" label="记录时间" />
<!-- 评估分数列 -->
<el-table-column prop="content.totalScore" label="评估分数" /> <el-table-column prop="content.totalScore" label="评估分数" />
<!-- 护理措施列 -->
<el-table-column prop="content.patientCareSessionsTableList" label="护理措施" /> <el-table-column prop="content.patientCareSessionsTableList" label="护理措施" />
<!-- 责任护士列 -->
<el-table-column prop="content.nurseSignature" label="责任护士" /> <el-table-column prop="content.nurseSignature" label="责任护士" />
<!-- 操作列编辑和删除按钮 -->
<el-table-column label="操作" align="center"> <el-table-column label="操作" align="center">
<template #default="scope"> <template #default="scope">
<el-button <el-button
@@ -36,9 +43,12 @@
</el-table-column> </el-table-column>
</el-table> </el-table>
<!-- 跌倒/坠床评估护理记录单表单区域 -->
<div name="跌倒/坠床评估护理记录单" class="changeMajor" style="width: 99.9%"> <div name="跌倒/坠床评估护理记录单" class="changeMajor" style="width: 99.9%">
<div> <div>
<!-- 表单主体 -->
<el-form ref="formRef" :model="form" style="width: 99.9%"> <el-form ref="formRef" :model="form" style="width: 99.9%">
<!-- 标题行 -->
<el-form-item style="text-align: center"> <el-form-item style="text-align: center">
<div <div
style=" style="
@@ -54,10 +64,12 @@
</div> </div>
</el-form-item> </el-form-item>
<!-- 日期时间选择器 -->
<el-form-item label="日期:" class="changeMajorFromItem" style="width: 100%"> <el-form-item label="日期:" class="changeMajorFromItem" style="width: 100%">
<el-row :span="20"> <el-row :span="20">
<el-col :span="8" style="padding-left: 0px !important"> <el-col :span="8" style="padding-left: 0px !important">
<el-form-item> <el-form-item>
<!-- 日期时间选择器 -->
<el-date-picker <el-date-picker
v-model="form.ZKDATE" v-model="form.ZKDATE"
type="datetime" type="datetime"
@@ -67,6 +79,7 @@
style="width: 800px" style="width: 800px"
:disabled="admissionDataForm !== undefined" :disabled="admissionDataForm !== undefined"
/> />
<!-- 时间选择器被注释掉 -->
<!-- <span style="margin-left: 5px">时间</span> <!-- <span style="margin-left: 5px">时间</span>
<el-time-picker <el-time-picker
v-model="form.ZKTIME" v-model="form.ZKTIME"
@@ -77,6 +90,7 @@
/> --> /> -->
</el-form-item> </el-form-item>
</el-col> </el-col>
<!-- 新增/保存按钮 -->
<el-col :span="5"> <el-col :span="5">
<el-button <el-button
v-if="!updateFlag" v-if="!updateFlag"
@@ -100,6 +114,7 @@
</el-row> </el-row>
</el-form-item> </el-form-item>
<!-- 危险因素评估表格 -->
<el-form-item style="padding-top: 10px; margin: 0px !important"> <el-form-item style="padding-top: 10px; margin: 0px !important">
<el-table <el-table
:data="dangerData" :data="dangerData"
@@ -107,6 +122,7 @@
:span-method="handleSpan" :span-method="handleSpan"
style="text-align: center" style="text-align: center"
> >
<!-- 动态生成表格列 -->
<el-table-column <el-table-column
v-for="column in dangerColumns" v-for="column in dangerColumns"
:key="column.key" :key="column.key"
@@ -115,6 +131,7 @@
:label="column.title" :label="column.title"
align="center" align="center"
/> />
<!-- 选择列复选框 -->
<el-table-column prop="id" label="选择" width="80" align="center"> <el-table-column prop="id" label="选择" width="80" align="center">
<template #default="{ row }"> <template #default="{ row }">
<el-checkbox v-model="row.checked" @change="handleDangerChange(row)" /> <el-checkbox v-model="row.checked" @change="handleDangerChange(row)" />
@@ -123,6 +140,7 @@
</el-table> </el-table>
</el-form-item> </el-form-item>
<!-- 总分显示 -->
<el-form-item <el-form-item
style="text-align: center; margin-bottom: 0px; padding: 0px" style="text-align: center; margin-bottom: 0px; padding: 0px"
class="changeMajorFromItem" class="changeMajorFromItem"
@@ -135,6 +153,7 @@
</el-row> </el-row>
</el-form-item> </el-form-item>
<!-- 护理措施表格 -->
<el-form-item style="padding-top: 10px"> <el-form-item style="padding-top: 10px">
<el-table <el-table
:data="nursingData" :data="nursingData"
@@ -142,6 +161,7 @@
:span-method="arraySpanMethod" :span-method="arraySpanMethod"
style="width: 100%" style="width: 100%"
> >
<!-- 动态生成表格列 -->
<el-table-column <el-table-column
v-for="column in nursingColumns" v-for="column in nursingColumns"
:key="column.key" :key="column.key"
@@ -150,6 +170,7 @@
:label="column.title" :label="column.title"
align="center" align="center"
/> />
<!-- 选择列复选框 -->
<el-table-column prop="id" label="选择" width="80" align="center"> <el-table-column prop="id" label="选择" width="80" align="center">
<template #default="{ row }"> <template #default="{ row }">
<el-checkbox v-model="row.checked" @change="handleNursingChange(row)" /> <el-checkbox v-model="row.checked" @change="handleNursingChange(row)" />
@@ -158,6 +179,7 @@
</el-table> </el-table>
</el-form-item> </el-form-item>
<!-- 护士签字输入框 -->
<el-form-item <el-form-item
style="text-align: center; margin-bottom: 0px; padding: 0px" style="text-align: center; margin-bottom: 0px; padding: 0px"
class="changeMajorFromItem" class="changeMajorFromItem"
@@ -177,6 +199,7 @@
</el-row> </el-row>
</el-form-item> </el-form-item>
<!-- 备注信息 -->
<el-form-item> <el-form-item>
<el-row :span="20"> <el-row :span="20">
<el-col :span="5"> <el-col :span="5">
@@ -197,22 +220,24 @@
</template> </template>
<script setup> <script setup>
// 组件选项定义
defineOptions({ defineOptions({
name: 'FallBedFallAssessment', name: '跌倒/坠床评估护理记录单',
}); });
// 导入所需模块
import { ref, reactive, computed, onMounted } from 'vue'; import { ref, reactive, computed, onMounted } from 'vue';
import { ElMessage } from 'element-plus'; import { ElMessage } from 'element-plus';
// import { webapp_ws_ajax_run, urlAddRandomNo } from '@/utils/grwebapp'; // 使用路由相关功能
// import { useRoute, useRouter } from 'vue-router';
// 响应式数据
const route = useRoute(); const route = useRoute();
const router = useRouter(); const router = useRouter();
// 定义引用变量
const queryRef = ref(); const queryRef = ref();
const formRef = ref(); const formRef = ref();
// 基本数据变量
const wardCode = ref(''); const wardCode = ref('');
const patientId = ref(''); const patientId = ref('');
const visitId = ref(''); const visitId = ref('');
@@ -226,17 +251,18 @@ const totalScore = ref(0);
const lastSubmit = ref(''); const lastSubmit = ref('');
const admissionDataForm = ref(route.params.admissionData); const admissionDataForm = ref(route.params.admissionData);
// 表单数据模型
const form = reactive({ const form = reactive({
ZKDATE: '', ZKDATE: '', // 日期
ZKTIME: '', ZKTIME: '', // 时间
recordTime: '', recordTime: '', // 记录时间
totalScore: 0, totalScore: 0, // 总分
bedFallRiskAssessmentList: [], bedFallRiskAssessmentList: [], // 跌倒风险评估列表
nurseSignature: '', nurseSignature: '', // 护士签名
patientCareSessionsCheckedList: [], patientCareSessionsCheckedList: [], // 护理措施选中列表
}); });
// 危险因素表格列 // 危险因素表格列配置
const dangerColumns = [ const dangerColumns = [
{ {
key: 'content', key: 'content',
@@ -301,7 +327,7 @@ const dangerData = ref([
{ id: '27', evalContent: '麻醉止痛剂', score: 2, checked: false }, { id: '27', evalContent: '麻醉止痛剂', score: 2, checked: false },
]); ]);
// 护理措施表格列 // 护理措施表格列配置
const nursingColumns = [ const nursingColumns = [
{ {
key: 'content', key: 'content',
@@ -338,21 +364,21 @@ const instructions = [
'3.评分≥5高度风险每周至少评估一次需采取适宜的预防措施同时填写《预防患者跌倒/坠床知情告知书》', '3.评分≥5高度风险每周至少评估一次需采取适宜的预防措施同时填写《预防患者跌倒/坠床知情告知书》',
]; ];
// 计算属性 // 计算属性:计算选中的危险因素总分
const calculate = computed(() => { const calculate = computed(() => {
return dangerData.value return dangerData.value
.filter((option) => option.checked) .filter((option) => option.checked)
.reduce((total, option) => total + option.score, 0); .reduce((total, option) => total + option.score, 0);
}); });
// 计算属性:判断表单是否为空
const isFormEmpty = computed(() => { const isFormEmpty = computed(() => {
return ( return (
form.ZKDATE === '' && form.ZKTIME === '' && form.recordTime === '' && form.nurseSignature === '' form.ZKDATE === '' && form.ZKTIME === '' && form.recordTime === '' && form.nurseSignature === ''
); );
}); });
// 方法 - 不再需要handleData方法通过表单输入和按钮加载数据 // 危险因素选择变化处理函数
const handleDangerChange = (row) => { const handleDangerChange = (row) => {
totalScore.value = calculate.value; totalScore.value = calculate.value;
form.bedFallRiskAssessmentList = dangerData.value form.bedFallRiskAssessmentList = dangerData.value
@@ -360,12 +386,14 @@ const handleDangerChange = (row) => {
.map((item) => item.id); .map((item) => item.id);
}; };
// 护理措施选择变化处理函数
const handleNursingChange = (row) => { const handleNursingChange = (row) => {
form.patientCareSessionsCheckedList = nursingData.value form.patientCareSessionsCheckedList = nursingData.value
.filter((item) => item.checked) .filter((item) => item.checked)
.map((item) => item.id); .map((item) => item.id);
}; };
// 初始化函数:加载模拟数据
const init = async () => { const init = async () => {
// 使用模拟数据不再调用后端API // 使用模拟数据不再调用后端API
try { try {
@@ -427,6 +455,7 @@ const init = async () => {
} }
}; };
// 危险因素表格合并单元格处理函数
const handleSpan = ({ row, column, rowIndex, columnIndex }) => { const handleSpan = ({ row, column, rowIndex, columnIndex }) => {
if (columnIndex === 0) { if (columnIndex === 0) {
if (rowIndex === 0) { if (rowIndex === 0) {
@@ -473,6 +502,7 @@ const handleSpan = ({ row, column, rowIndex, columnIndex }) => {
return [1, 1]; return [1, 1];
}; };
// 护理措施表格合并单元格处理函数
const arraySpanMethod = ({ row, column, rowIndex, columnIndex }) => { const arraySpanMethod = ({ row, column, rowIndex, columnIndex }) => {
// 护理措施 // 护理措施
if (columnIndex === 0) { if (columnIndex === 0) {
@@ -489,8 +519,9 @@ const arraySpanMethod = ({ row, column, rowIndex, columnIndex }) => {
return [1, 1]; return [1, 1];
}; };
// 提交表单处理函数
const onSubmit = async () => { const onSubmit = async () => {
// 检查上次提交时间 // 检查上次提交时间,防止重复提交
if (lastSubmit.value && new Date() - lastSubmit.value < 2000) { if (lastSubmit.value && new Date() - lastSubmit.value < 2000) {
ElMessage.error('禁止重复提交!'); ElMessage.error('禁止重复提交!');
return; return;
@@ -562,6 +593,7 @@ const onSubmit = async () => {
} }
}; };
// 编辑记录处理函数
const handleUpdate = (row) => { const handleUpdate = (row) => {
const loginUser = JSON.parse(window.localStorage.getItem('loginUser')); const loginUser = JSON.parse(window.localStorage.getItem('loginUser'));
@@ -591,6 +623,7 @@ const handleUpdate = (row) => {
} }
}; };
// 重置表单函数
const reset = () => { const reset = () => {
Object.assign(form, { Object.assign(form, {
ZKDATE: '', ZKDATE: '',
@@ -623,6 +656,7 @@ const reset = () => {
} }
}; };
// 删除记录处理函数
const handleDelete = (row) => { const handleDelete = (row) => {
const loginUser = JSON.parse(window.localStorage.getItem('loginUser')); const loginUser = JSON.parse(window.localStorage.getItem('loginUser'));
@@ -646,6 +680,7 @@ const handleDelete = (row) => {
} }
}; };
// 打印预览函数(暂未实现)
const dc_ajax_preview = () => { const dc_ajax_preview = () => {
var args = { var args = {
report: urlAddRandomNo('./grf/NurseRecord_Pressure_208.grf'), report: urlAddRandomNo('./grf/NurseRecord_Pressure_208.grf'),
@@ -656,6 +691,7 @@ const dc_ajax_preview = () => {
webapp_ws_ajax_run(args); webapp_ws_ajax_run(args);
}; };
// 数据转换函数,用于报表打印
const transformData = () => { const transformData = () => {
const jsonDate = [...tableDataSource.value]; const jsonDate = [...tableDataSource.value];
@@ -802,7 +838,7 @@ const transformData = () => {
return transformedData; return transformedData;
}; };
// 生命周期钩子 // 组件挂载后执行的生命周期函数
onMounted(() => { onMounted(() => {
try { try {
// 安全获取用户信息 // 安全获取用户信息
@@ -831,6 +867,7 @@ onMounted(() => {
</script> </script>
<style scoped> <style scoped>
/* 页面样式定义 */
.business { .business {
background: white; background: white;
border-radius: 5px; border-radius: 5px;
@@ -894,4 +931,10 @@ onMounted(() => {
margin-bottom: 0px !important; margin-bottom: 0px !important;
} }
} }
/* 备注信息列表样式 */
.instructions-list {
list-style-type: none;
padding-left: 0;
}
</style> </style>

View File

@@ -1,17 +1,42 @@
// 动态引入 template 目录下的所有 .vue 文件 /**
* 模板组件注册模块
* 动态引入 template 目录下的所有 .vue 文件,并将它们注册为全局组件
*/
// 动态引入 template 目录下的所有 .vue 文件(包括中文命名的文件)
// 使用 { eager: true } 表示立即加载所有匹配的文件
const templates = import.meta.glob('./*.vue', { eager: true }); const templates = import.meta.glob('./*.vue', { eager: true });
// 存储所有加载的组件
const components = []; const components = [];
// 遍历所有引入的文件 // 遍历所有引入的文件
for (const path in templates) { for (const path in templates) {
try {
// 获取组件的默认导出
const component = templates[path].default; const component = templates[path].default;
// 检查组件是否有 name 属性,如果没有则跳过
if (component && component.name) {
components.push(component); components.push(component);
} else {
console.warn(`组件 ${path} 缺少 name 属性,将不会被注册`);
}
} catch (error) {
console.error(`加载组件 ${path} 时出错:`, error);
}
} }
/**
* 注册所有组件到 Vue 应用实例
* @param {Object} app - Vue 应用实例
*/
const registerComponents = (app) => { const registerComponents = (app) => {
components.forEach((component) => { components.forEach((component) => {
// 使用组件的 name 属性作为组件名称进行注册
app.component(component.name, component); app.component(component.name, component);
}) });
} };
export { components, registerComponents };
// 导出组件数组和注册函数
export { components, registerComponents };

View File

@@ -1,15 +1,19 @@
<template> <template>
<!-- 门诊病历表单主容器 -->
<div class="medical-form"> <div class="medical-form">
<!-- 患者基本信息展示区域 -->
<div class="patient-name"> <div class="patient-name">
患者姓名{{ patient?.patientName || '未知' }} &nbsp;&nbsp; 病历号{{ 患者姓名{{ patient?.patientName || '未知' }} &nbsp;&nbsp; 病历号{{
patient?.busNo || '未知' patient?.busNo || '未知'
}} }}
</div> </div>
<!-- 医院名称和标题 -->
<h2 style="text-align: center">{{ userStore.hospitalName }}</h2> <h2 style="text-align: center">{{ userStore.hospitalName }}</h2>
<h2 style="text-align: center">门诊病历</h2> <h2 style="text-align: center">门诊病历</h2>
<!-- 滚动内容区域 --> <!-- 滚动内容区域 -->
<div class="form-scroll-container"> <div class="form-scroll-container">
<!-- Element Plus表单组件 -->
<el-form <el-form
ref="formRef" ref="formRef"
:model="formData" :model="formData"
@@ -18,34 +22,40 @@
label-align="left" label-align="left"
class="medical-full-form" class="medical-full-form"
> >
<!-- 基础信息区域标题 -->
<h4 class="section-title">基础信息</h4> <h4 class="section-title">基础信息</h4>
<!-- 1. 基础信息单行自适应排列 --> <!-- 1. 基础信息单行自适应排列 -->
<el-form-item class="form-section"> <el-form-item class="form-section">
<div class="single-row-layout"> <div class="single-row-layout">
<!-- 身高输入项 -->
<el-form-item label="身高" prop="height" class="row-item"> <el-form-item label="身高" prop="height" class="row-item">
<div class="input-with-unit"> <div class="input-with-unit">
<el-input v-model="formData.height" type="text" placeholder="请输入" /> <el-input v-model="formData.height" type="text" placeholder="请输入" />
<span class="unit">cm</span> <span class="unit">cm</span>
</div> </div>
</el-form-item> </el-form-item>
<!-- 体重输入项 -->
<el-form-item label="体重" prop="weight" class="row-item"> <el-form-item label="体重" prop="weight" class="row-item">
<div class="input-with-unit"> <div class="input-with-unit">
<el-input v-model="formData.weight" type="text" placeholder="请输入" /> <el-input v-model="formData.weight" type="text" placeholder="请输入" />
<span class="unit">kg</span> <span class="unit">kg</span>
</div> </div>
</el-form-item> </el-form-item>
<!-- 体温输入项 -->
<el-form-item label="体温" prop="temperature" class="row-item"> <el-form-item label="体温" prop="temperature" class="row-item">
<div class="input-with-unit"> <div class="input-with-unit">
<el-input v-model="formData.temperature" type="text" placeholder="请输入" /> <el-input v-model="formData.temperature" type="text" placeholder="请输入" />
<span class="unit"></span> <span class="unit"></span>
</div> </div>
</el-form-item> </el-form-item>
<!-- 脉搏输入项 -->
<el-form-item label="脉搏" prop="pulse" class="row-item"> <el-form-item label="脉搏" prop="pulse" class="row-item">
<div class="input-with-unit"> <div class="input-with-unit">
<el-input v-model="formData.pulse" type="text" placeholder="请输入" /> <el-input v-model="formData.pulse" type="text" placeholder="请输入" />
<span class="unit">/</span> <span class="unit">/</span>
</div> </div>
</el-form-item> </el-form-item>
<!-- 发病日期选择项 -->
<el-form-item label="发病日期" prop="onsetDate" class="row-item"> <el-form-item label="发病日期" prop="onsetDate" class="row-item">
<el-date-picker <el-date-picker
v-model="formData.onsetDate" v-model="formData.onsetDate"
@@ -58,10 +68,13 @@
</el-form-item> </el-form-item>
</div> </div>
</el-form-item> </el-form-item>
<!-- 病史信息区域标题 -->
<h4 class="section-title">病史信息</h4> <h4 class="section-title">病史信息</h4>
<!-- 2. 病史信息单行自适应排列新增调整 --> <!-- 2. 病史信息单行自适应排列新增调整 -->
<el-form-item class="form-section"> <el-form-item class="form-section">
<div class="single-row-layout"> <div class="single-row-layout">
<!-- 现病史输入项 -->
<el-form-item label="现病史" prop="presentIllness" class="row-item history-item"> <el-form-item label="现病史" prop="presentIllness" class="row-item history-item">
<el-input <el-input
v-model="formData.presentIllness" v-model="formData.presentIllness"
@@ -70,9 +83,11 @@
autosize autosize
/> />
</el-form-item> </el-form-item>
<!-- 既往史输入项 -->
<el-form-item label="既往史" prop="pastIllness" class="row-item history-item"> <el-form-item label="既往史" prop="pastIllness" class="row-item history-item">
<el-input v-model="formData.pastIllness" type="textarea" placeholder="无" autosize /> <el-input v-model="formData.pastIllness" type="textarea" placeholder="无" autosize />
</el-form-item> </el-form-item>
<!-- 个人史输入项 -->
<el-form-item label="个人史" prop="personalHistory" class="row-item history-item"> <el-form-item label="个人史" prop="personalHistory" class="row-item history-item">
<el-input <el-input
v-model="formData.personalHistory" v-model="formData.personalHistory"
@@ -81,6 +96,7 @@
autosize autosize
/> />
</el-form-item> </el-form-item>
<!-- 过敏史输入项 -->
<el-form-item label="过敏史" prop="allergyHistory" class="row-item history-item"> <el-form-item label="过敏史" prop="allergyHistory" class="row-item history-item">
<el-input <el-input
v-model="formData.allergyHistory" v-model="formData.allergyHistory"
@@ -89,6 +105,7 @@
autosize autosize
/> />
</el-form-item> </el-form-item>
<!-- 家族史输入项 -->
<el-form-item label="家族史" prop="familyHistory" class="row-item history-item"> <el-form-item label="家族史" prop="familyHistory" class="row-item history-item">
<el-input <el-input
v-model="formData.familyHistory" v-model="formData.familyHistory"
@@ -99,6 +116,8 @@
</el-form-item> </el-form-item>
</div> </div>
</el-form-item> </el-form-item>
<!-- 主诉查体(治疗)处置辅助检查区域标题 -->
<h4 class="section-title">主诉查体(治疗)处置辅助检查</h4> <h4 class="section-title">主诉查体(治疗)处置辅助检查</h4>
<!-- 3. 主诉必填 --> <!-- 3. 主诉必填 -->
<el-form-item label="主诉" prop="complaint" class="required form-item-single"> <el-form-item label="主诉" prop="complaint" class="required form-item-single">
@@ -111,6 +130,7 @@
/> />
</el-form-item> </el-form-item>
<!-- 4. 查体处理辅助检查 --> <!-- 4. 查体处理辅助检查 -->
<!-- 查体(治疗)输入项 -->
<el-form-item label="查体(治疗)" prop="physicalExam" class="form-item-single"> <el-form-item label="查体(治疗)" prop="physicalExam" class="form-item-single">
<el-input <el-input
v-model="formData.physicalExam" v-model="formData.physicalExam"
@@ -121,6 +141,7 @@
/> />
</el-form-item> </el-form-item>
<!-- 处置输入项 -->
<el-form-item label="处置" prop="treatment" class="form-item-single"> <el-form-item label="处置" prop="treatment" class="form-item-single">
<el-input <el-input
v-model="formData.treatment" v-model="formData.treatment"
@@ -131,6 +152,7 @@
/> />
</el-form-item> </el-form-item>
<!-- 辅助检查输入项 -->
<el-form-item label="辅助检查" prop="auxiliaryExam" class="form-item-single"> <el-form-item label="辅助检查" prop="auxiliaryExam" class="form-item-single">
<el-input <el-input
v-model="formData.auxiliaryExam" v-model="formData.auxiliaryExam"
@@ -146,12 +168,14 @@
</template> </template>
<script setup> <script setup>
// 导入Vue相关功能和组件
import { reactive, ref, onBeforeMount, onMounted, watch } from 'vue'; import { reactive, ref, onBeforeMount, onMounted, watch } from 'vue';
import useUserStore from '../store/modules/user'; import useUserStore from '../store/modules/user';
import { ElInput, ElMessage, ElForm, ElFormItem } from 'element-plus'; import { ElInput, ElMessage, ElForm, ElFormItem } from 'element-plus';
import { patientInfo } from '../views/doctorstation/components/store/patient'; import { patientInfo } from '../views/doctorstation/components/store/patient';
import { pa } from 'element-plus/es/locales.mjs'; import { pa } from 'element-plus/es/locales.mjs';
// 定义组件选项
defineOptions({ defineOptions({
name: 'OutpatientMedicalRecord', name: 'OutpatientMedicalRecord',
components: { ElInput, ElMessage, ElForm, ElFormItem }, components: { ElInput, ElMessage, ElForm, ElFormItem },
@@ -164,33 +188,42 @@ defineOptions({
// required: true, // required: true,
// }, // },
// }); // });
// 定义组件接收的属性(目前为空)
const props = defineProps({}); const props = defineProps({});
// 定义组件触发的事件
const emits = defineEmits(['submitOk']); const emits = defineEmits(['submitOk']);
// 数据初始化 // 数据初始化
// 获取用户store实例用于获取医院名称等全局信息
const userStore = useUserStore(); const userStore = useUserStore();
// 患者信息引用,存储当前就诊患者的基本信息
const patient = ref(null); const patient = ref(null);
// 表单引用,用于访问表单实例进行验证等操作
const formRef = ref(null); const formRef = ref(null);
// 表单数据(全部字符类型) // 表单数据(全部字符类型)
// 存储门诊病历表单的所有字段数据
const formData = reactive({ const formData = reactive({
height: '', // 身高 height: '', // 身高(cm)
weight: '', // 体重 weight: '', // 体重(kg)
temperature: '', // 体温 temperature: '', // 体温(℃)
pulse: '', // 脉搏 pulse: '', // 脉搏(次/分)
onsetDate: '', // 发病日期 onsetDate: '', // 发病日期
complaint: '', // 主诉(必填) complaint: '', // 主诉(必填
presentIllness: '', // 现病史 presentIllness: '', // 现病史
pastIllness: '', // 既往史 pastIllness: '', // 既往史
personalHistory: '', // 个人史 personalHistory: '', // 个人史
allergyHistory: '', // 过敏史 allergyHistory: '', // 过敏史
physicalExam: '', // 查体 physicalExam: '', // 查体结果
treatment: '', // 处理 treatment: '', // 处理方案
auxiliaryExam: '', // 辅助检查 auxiliaryExam: '', // 辅助检查结果
familyHistory: '', // 家族史 familyHistory: '', // 家族史
}); });
// 表单校验规则 // 表单校验规则
// 定义表单字段的验证规则,目前仅主诉为必填项
const rules = reactive({ const rules = reactive({
complaint: [ complaint: [
{ {
@@ -202,15 +235,21 @@ const rules = reactive({
}); });
// 提交函数 // 提交函数
// 用于触发表单验证并提交数据到父组件
const submit = () => { const submit = () => {
// 表单验证
formRef.value.validate((isValid) => { formRef.value.validate((isValid) => {
if (isValid) { if (isValid) {
// 触发submitOk事件传递表单数据
emits('submitOk', formData); emits('submitOk', formData);
// 显示成功消息
ElMessage.success('提交成功'); ElMessage.success('提交成功');
} }
}); });
}; };
// 日期格式化工具
// 日期格式化工具函数
// 将Date对象格式化为 YYYY-MM-DD HH:mm 格式的字符串
const formatDateTime = (date) => { const formatDateTime = (date) => {
const year = date.getFullYear(); const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0'); const month = String(date.getMonth() + 1).padStart(2, '0');
@@ -219,17 +258,23 @@ const formatDateTime = (date) => {
const minute = String(date.getMinutes()).padStart(2, '0'); const minute = String(date.getMinutes()).padStart(2, '0');
return `${year}-${month}-${day} ${hour}:${minute}`; return `${year}-${month}-${day} ${hour}:${minute}`;
}; };
// 表单数据赋值
// 表单数据赋值函数
// 用于外部组件向表单填充已有数据
const setFormData = (data) => { const setFormData = (data) => {
if (data) { if (data) {
// 将传入的数据合并到表单数据中
Object.assign(formData, data); Object.assign(formData, data);
} }
}; };
// 生命周期 // 生命周期钩子 - 组件挂载前
onBeforeMount(() => {}); onBeforeMount(() => {});
// 生命周期钩子 - 组件挂载后
onMounted(() => { onMounted(() => {
console.log('当前患者信息:', patientInfo); console.log('当前患者信息:', patientInfo);
// 从store获取患者信息
patient.value = patientInfo.value; patient.value = patientInfo.value;
// 初始化发病日期为当前时间 // 初始化发病日期为当前时间
if (!formData.onsetDate) { if (!formData.onsetDate) {
@@ -238,6 +283,7 @@ onMounted(() => {
}); });
// 监听患者信息变化,实现联动显示 // 监听患者信息变化,实现联动显示
// 当patientInfo发生变化时更新本地patient引用
watch( watch(
() => patientInfo.value, () => patientInfo.value,
(newPatientInfo) => { (newPatientInfo) => {
@@ -246,7 +292,8 @@ watch(
{ deep: true } { deep: true }
); );
// 暴露接口 // 暴露接口供父组件调用
// 将formData、submit方法和setFormData方法暴露给父组件使用
defineExpose({ formData, submit, setFormData }); defineExpose({ formData, submit, setFormData });
</script> </script>

View File

@@ -1,21 +1,50 @@
// 导入 API 函数,用于从服务器获取带有选项列表的数据
import { getListWithOptionList } from '@/views/basicmanage/caseTemplatesStatistics/api'; import { getListWithOptionList } from '@/views/basicmanage/caseTemplatesStatistics/api';
// 导入 Vue 3 的组合式 APIonMounted组件挂载后执行和 ref响应式数据
import { onMounted, ref } from 'vue'; import { onMounted, ref } from 'vue';
// 创建响应式数据:统计选项列表,初始为空数组
const statisticsOptionList = ref([]); const statisticsOptionList = ref([]);
/**
* 初始化统计选项列表数据
* 异步函数,通过 API 获取数据并更新到响应式变量中
*/
const initStatic = async () => { const initStatic = async () => {
try { try {
// 调用 API 获取数据
const res = await getListWithOptionList(); const res = await getListWithOptionList();
// 将获取到的数据赋值给响应式变量
statisticsOptionList.value = res.data; statisticsOptionList.value = res.data;
} catch (error) { } catch (error) {
// 错误处理:打印错误信息到控制台
console.log(error); console.log(error);
} }
}; };
/**
* Vue 3 组合式函数:用于获取和管理统计选项列表
* @returns {Object} 返回包含响应式数据和方法的对象
*/
export default function useOptionsList() { export default function useOptionsList() {
// 组件挂载后自动初始化数据
onMounted(() => {
initStatic(); initStatic();
});
/**
* 根据代码获取对应的选项列表
* @param {string} code - 统计类型代码
* @returns {Array} 返回匹配的选项列表,如果没有匹配则返回空数组
*/
const getStatisticsOptionList = (code) => { const getStatisticsOptionList = (code) => {
// 在统计选项列表中查找匹配代码的项,然后返回其 optionList 属性,如果没有找到则返回空数组
return statisticsOptionList.value.find((item) => item.code === code)?.optionList || []; return statisticsOptionList.value.find((item) => item.code === code)?.optionList || [];
}; };
// 返回响应式数据和方法供组件使用
return { return {
statisticsOptionList, statisticsOptionList, // 完整的统计选项列表
getStatisticsOptionList, getStatisticsOptionList, // 根据代码获取选项列表的方法
}; };
} }

View File

@@ -0,0 +1,44 @@
<template>
<div class="template-content">
<div class="template-header">
<h3>股骨头坏死(模板11111111)</h3>
</div>
<div class="template-body">
<p>主诉左侧髋部疼痛X个月加重1周</p>
<p>现病史患者X个月前无明显诱因出现左侧髋部疼痛活动后加重休息后减轻未予重视1周前疼痛加重行走困难遂来我院就诊</p>
<p>既往史否认高血压糖尿病冠心病等慢性病史否认手术外伤史否认药物过敏史</p>
<p>体格检查左侧髋关节压痛(+)活动受限左下肢肌力下降</p>
<p>辅助检查DR示左侧股骨头坏死</p>
<p>诊断左侧股骨头坏死</p>
<p>治疗方案1. 避免负重2. 药物治疗3. 必要时手术治疗</p>
</div>
</div>
</template>
<script setup>
defineOptions({
name: '股骨头坏死(模板11111111)'
})
// 可以在这里添加组件逻辑
</script>
<style scoped>
.template-content {
background-color: white;
border: 1px solid #ddd;
border-radius: 4px;
padding: 15px;
min-height: 300px;
}
.template-header {
border-bottom: 1px solid #eee;
padding-bottom: 10px;
margin-bottom: 15px;
}
.template-body p {
margin-bottom: 10px;
line-height: 1.5;
}
</style>

View File

@@ -27,7 +27,7 @@
style="width: 100%" style="width: 100%"
class="clinic-room-table" class="clinic-room-table"
> >
<el-table-column prop="id" label="ID" width="80" align="center" /> <el-table-column prop="id" label="ID" width="180" align="center" />
<el-table-column prop="roomName" label="诊室名称" width="160" align="center" show-overflow-tooltip /> <el-table-column prop="roomName" label="诊室名称" width="160" align="center" show-overflow-tooltip />
<el-table-column prop="department" label="科室名称" width="160" align="center" show-overflow-tooltip /> <el-table-column prop="department" label="科室名称" width="160" align="center" show-overflow-tooltip />
<el-table-column prop="building" label="诊室楼号" width="120" align="center" show-overflow-tooltip /> <el-table-column prop="building" label="诊室楼号" width="120" align="center" show-overflow-tooltip />
@@ -40,7 +40,7 @@
</el-tag> </el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="remarks" label="备注" min-width="140" align="center" show-overflow-tooltip /> <el-table-column prop="remarks" label="备注" min-width="100" align="center" show-overflow-tooltip />
<el-table-column prop="void" label="作废" width="90" align="center"> <el-table-column prop="void" label="作废" width="90" align="center">
<template #default="scope"> <template #default="scope">
<el-tag :type="scope.row.void ? 'danger' : 'success'"> <el-tag :type="scope.row.void ? 'danger' : 'success'">
@@ -48,7 +48,7 @@
</el-tag> </el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" width="200" align="center" fixed="right"> <el-table-column label="操作" width="250" align="center" fixed="right">
<template #default="scope"> <template #default="scope">
<el-button <el-button
type="primary" type="primary"

View File

@@ -98,10 +98,24 @@
/> />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="maxNumber" label="限号数量" width="80"></el-table-column> <el-table-column prop="maxNumber" label="限号数量" width="80">
<template #default="scope">
<el-input
v-model="scope.row.maxNumber"
type="number"
:disabled="!isEditMode"
/>
</template>
</el-table-column>
<el-table-column prop="record" label="号源记录" width="80"> <el-table-column prop="record" label="号源记录" width="80">
<template #default="scope"> <template #default="scope">
<el-icon><View /></el-icon> <el-icon
@click="handleViewRecord(scope.row)"
class="record-icon"
title="查看号源记录"
>
<View />
</el-icon>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="appointmentItem" label="挂号项目" width="120"> <el-table-column prop="appointmentItem" label="挂号项目" width="120">
@@ -186,13 +200,32 @@
<el-button @click="handleCancel">取消</el-button> <el-button @click="handleCancel">取消</el-button>
</div> </div>
</div> </div>
<!-- 号源记录对话框 -->
<el-dialog
v-model="recordDialogVisible"
title="号源记录"
width="30%"
:close-on-click-modal="true"
>
<div class="appointment-records">
<div class="record-item" v-for="record in appointmentRecords" :key="record.index">
<span class="record-time">{{ record.time }}</span>
</div>
</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="recordDialogVisible = false">确定</el-button>
</div>
</template>
</el-dialog>
</div> </div>
</template> </template>
<script setup name="DoctorSchedule"> <script setup name="DoctorSchedule">
import { ref, onMounted, computed } from 'vue' import { ref, onMounted, computed, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
import { ElMessage } from 'element-plus' import { ElMessage, ElMessageBox, ElDialog } from 'element-plus'
import { View } from '@element-plus/icons-vue' import { View } from '@element-plus/icons-vue'
// 路由和导航 // 路由和导航
@@ -264,7 +297,7 @@ const generateWeekSchedule = (startDate) => {
endTime: slot.endTime, endTime: slot.endTime,
doctorName: '', doctorName: '',
room: '', room: '',
maxNumber: 20, maxNumber: '',
appointmentItem: '', appointmentItem: '',
registrationFee: '', registrationFee: '',
clinicItem: '', clinicItem: '',
@@ -299,6 +332,59 @@ const handleDeleteSchedule = (row) => {
ElMessage.info('删除排班功能待实现') ElMessage.info('删除排班功能待实现')
} }
// 号源记录对话框相关
const recordDialogVisible = ref(false)
const currentRow = ref(null)
const appointmentRecords = ref([])
// 计算号源记录
const calculateAppointmentRecords = (row) => {
const { startTime, endTime, maxNumber } = row
// 将时间转换为分钟数
const [startHour, startMinute] = startTime.split(':').map(Number)
const [endHour, endMinute] = endTime.split(':').map(Number)
const startTotalMinutes = startHour * 60 + startMinute
const endTotalMinutes = endHour * 60 + endMinute
// 计算总时长和间隔
const totalDuration = endTotalMinutes - startTotalMinutes
const interval = Math.floor(totalDuration / maxNumber)
// 生成号源记录
const records = []
for (let i = 0; i < maxNumber; i++) {
const minutes = startTotalMinutes + i * interval
const hour = Math.floor(minutes / 60).toString().padStart(2, '0')
const minute = (minutes % 60).toString().padStart(2, '0')
records.push({
index: i + 1,
time: `${hour}:${minute}`
})
}
return records
}
// 查看号源记录
const handleViewRecord = (row) => {
// 验证开始时间、结束时间和限号数量
if (!row.startTime || !row.endTime || !row.maxNumber) {
ElMessageBox.confirm('请先设置开始时间、结束时间和限号数量', '', {
confirmButtonText: '确定',
type: 'warning',
showCancelButton: false
})
return
}
// 计算号源记录
currentRow.value = row
appointmentRecords.value = calculateAppointmentRecords(row)
recordDialogVisible.value = true
}
// 保存排班 // 保存排班
const handleSave = () => { const handleSave = () => {
ElMessage.success('排班保存成功') ElMessage.success('排班保存成功')
@@ -316,6 +402,15 @@ const handleCancel = () => {
onMounted(() => { onMounted(() => {
initData() initData()
}) })
// 监听路由参数变化,重新初始化数据
watch(
() => [route.params.deptId, route.query.mode],
() => {
initData()
},
{ deep: true }
)
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
@@ -462,9 +557,55 @@ onMounted(() => {
width: 100%; width: 100%;
} }
.record-icon {
font-size: 18px;
color: #409eff;
cursor: pointer;
transition: color 0.2s;
}
.record-icon:hover {
color: #66b1ff;
}
.bottom-buttons { .bottom-buttons {
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
gap: 16px; gap: 16px;
} }
/* 号源记录对话框样式 */
.appointment-records {
max-height: 300px;
overflow-y: auto;
padding: 10px 0;
}
.record-item {
padding: 8px 0;
border-bottom: 1px solid #f0f0f0;
}
.record-item:last-child {
border-bottom: none;
}
.record-time {
font-size: 16px;
color: #333;
}
.dialog-footer {
text-align: center;
}
/* 隐藏数字输入框的增减按钮 */
:deep(.el-input__inner[type="number"]) {
-moz-appearance: textfield;
}
:deep(.el-input__inner[type="number"])::-webkit-outer-spin-button,
:deep(.el-input__inner[type="number"])::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
</style> </style>

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="appoinmentmanage-container"> <div class="appoinmentmanage-container">
<div class="appoinmentmanage-header"> <div class="appoinmentmanage-header">
<h2 class="appoinmentmanage-title">预约管理</h2> <h2 class="appoinmentmanage-title">科室名称管理</h2>
</div> </div>
<div class="appoinmentmanage-content"> <div class="appoinmentmanage-content">

View File

@@ -219,6 +219,7 @@ const templateName = ref('');
// 事件 // 事件
const emits = defineEmits(['save']); const emits = defineEmits(['save']);
const { proxy } = getCurrentInstance(); const { proxy } = getCurrentInstance();
console.log('EMR组件初始化proxy:', proxy);
// 监听表单变化 // 监听表单变化
watch( watch(
@@ -325,16 +326,107 @@ function cancel() {
// 暴露方法给父组件 // 暴露方法给父组件
defineExpose({ defineExpose({
getDetail(encounterId) { getDetail(encounterId) {
getEmrDetail(encounterId).then((res) => { console.log('开始获取病历详情encounterId:', encounterId);
if (res.data) {
try { // 立即初始化form.value为空对象确保页面有内容显示
form.value = JSON.parse(res.data.contextJson) || {};
} catch (e) {
form.value = {}; form.value = {};
// 检查API函数是否存在
if (typeof getEmrDetail !== 'function') {
console.error('getEmrDetail函数未定义');
if (proxy) {
proxy.$modal.msgError('获取病历详情失败API函数未定义');
} }
emits('save', true); return;
}
// 添加超时处理,防止请求一直挂起
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => {
reject(new Error('获取病历详情请求超时'));
}, 10000); // 10秒超时
});
// 使用Promise.race处理正常请求和超时
Promise.race([getEmrDetail(encounterId), timeoutPromise])
.then((res) => {
console.log('获取病历详情成功,返回完整数据:', JSON.stringify(res, null, 2));
// 检查响应是否有效
if (!res) {
console.error('API返回结果为空');
if (proxy) {
proxy.$modal.msgError('获取病历详情失败API返回结果为空');
}
return;
}
console.log('res存在类型:', typeof res);
console.log('res的属性:', Object.keys(res));
// 检查响应码
if (res.code !== 200) {
console.error('API返回错误代码:', res.code);
if (proxy) {
proxy.$modal.msgError('获取病历详情失败:' + (res.msg || '未知错误'));
}
return;
}
// 检查数据是否存在
if (!res.data) {
console.log('res.data为空使用默认值');
return;
}
console.log('res.data存在类型:', typeof res.data);
console.log('res.data的属性:', Object.keys(res.data));
// 处理contextJson
try {
if (res.data.contextJson) {
console.log('contextJson存在值:', res.data.contextJson);
console.log('contextJson类型:', typeof res.data.contextJson);
// 检查contextJson类型
if (typeof res.data.contextJson === 'string') {
// 尝试解析JSON字符串
const parsedData = JSON.parse(res.data.contextJson);
// 确保解析结果是对象
if (typeof parsedData === 'object' && parsedData !== null) {
form.value = parsedData;
console.log('解析后的病历数据:', JSON.stringify(form.value, null, 2));
} else { } else {
form.value = {}; form.value = {};
console.error('contextJson解析结果不是有效对象:', parsedData);
}
} else if (typeof res.data.contextJson === 'object') {
// 如果已经是对象,直接使用
form.value = res.data.contextJson;
console.log('直接使用contextJson作为对象:', JSON.stringify(form.value, null, 2));
} else {
form.value = {};
console.error('contextJson类型无效:', typeof res.data.contextJson);
}
} else {
console.log('contextJson为空使用默认值');
}
} catch (e) {
form.value = {};
console.error('病历数据解析失败:', e);
console.error('解析失败的contextJson值:', res.data.contextJson);
if (proxy) {
proxy.$modal.msgError('病历数据解析失败');
}
}
emits('save', true);
})
.catch((error) => {
// 处理API调用失败或超时的情况
console.error('获取病历详情失败:', error);
if (proxy) {
proxy.$modal.msgError('获取病历详情失败:' + (error.message || '未知错误'));
} }
}); });
}, },

View File

@@ -1493,6 +1493,7 @@ const { proxy } = getCurrentInstance();
const inputRefs = ref({}); // 存储输入框实例,格式: { rowIndex: { fieldName: el } } const inputRefs = ref({}); // 存储输入框实例,格式: { rowIndex: { fieldName: el } }
const requiredProps = ref([]); // 存储必填项 prop 顺序 const requiredProps = ref([]); // 存储必填项 prop 顺序
const totalAmount = ref(0); const totalAmount = ref(0);
const groupMarkers = ref([]); // 存储分组标记,用于显示层级关系
const { method_code, unit_code, rate_code, distribution_category_code, drord_doctor_type } = proxy.useDict( const { method_code, unit_code, rate_code, distribution_category_code, drord_doctor_type } = proxy.useDict(
'method_code', 'method_code',
'unit_code', 'unit_code',

View File

@@ -20,16 +20,16 @@
<el-icon <el-icon
class="delete-icon" class="delete-icon"
title="删除处方单" title="删除处方单"
@click="handleDeletePrescriptionClick(index)" @click="handleDeletePrescriptionClick(pIndex)"
:class="{ 'disabled-icon': isPrescriptionDeletable(index) !== true }" :class="{ 'disabled-icon': isPrescriptionDeletable(pIndex) !== true }"
style="font-size: 20px !important; margin-left: 10px; color: #f56c6c" style="font-size: 20px !important; margin-left: 10px; color: #f56c6c"
> >
<minus /> <minus />
</el-icon> </el-icon>
</div> </div>
<div class="summary"> <div class="summary">
<span class="summary-item">药品数: {{ getPrescriptionMedicineCount(index) }}</span> <span class="summary-item">药品数: {{ getPrescriptionMedicineCount(pIndex) }}</span>
<span class="summary-item">总价: ¥ {{ getPrescriptionTotalPrice(index) }}</span> <span class="summary-item">总价: ¥ {{ getPrescriptionTotalPrice(pIndex) }}</span>
</div> </div>
</div> </div>
<div> <div>
@@ -570,7 +570,10 @@ function getList() {
} }
function getListInfo(addNewRow) { function getListInfo(addNewRow) {
// 确保isAdding变量存在
if (typeof isAdding !== 'undefined') {
isAdding.value = false; isAdding.value = false;
}
// 确保有患者信息 // 确保有患者信息
if (!props.patientInfo || !props.patientInfo.encounterId) { if (!props.patientInfo || !props.patientInfo.encounterId) {
@@ -580,13 +583,17 @@ function getListInfo(addNewRow) {
getTcmAdviceList({ encounterId: props.patientInfo.encounterId }).then((res) => { getTcmAdviceList({ encounterId: props.patientInfo.encounterId }).then((res) => {
if (res && res.data && Array.isArray(res.data)) { if (res && res.data && Array.isArray(res.data)) {
prescriptionList.value = res.data.map((item) => { // 清空当前处方列表
tcmPrescriptionList.value = [];
// 处理返回的数据
res.data.forEach((item) => {
try { try {
// 解析contentJson获取完整的医嘱数据 // 解析contentJson获取完整的医嘱数据
const contentData = item.contentJson ? JSON.parse(item.contentJson) : {}; const contentData = item.contentJson ? JSON.parse(item.contentJson) : {};
// 合并基础信息和contentJson中的详细信息 // 创建一个新的处方对象
return { const newPrescription = {
...item, ...item,
...contentData, ...contentData,
// 确保关键显示字段存在 // 确保关键显示字段存在
@@ -596,11 +603,14 @@ function getListInfo(addNewRow) {
diagnosisName: contentData.diagnosisName || item.diagnosisName || '', diagnosisName: contentData.diagnosisName || item.diagnosisName || '',
positionName: contentData.positionName || item.positionName || '', positionName: contentData.positionName || item.positionName || '',
doseUnitCode_dictText: contentData.doseUnitCode_dictText || item.doseUnitCode_dictText || '', doseUnitCode_dictText: contentData.doseUnitCode_dictText || item.doseUnitCode_dictText || '',
chineseHerbsDoseQuantity: contentData.chineseHerbsDoseQuantity || item.chineseHerbsDoseQuantity || '' chineseHerbsDoseQuantity: contentData.chineseHerbsDoseQuantity || item.chineseHerbsDoseQuantity || '',
prescriptionList: [contentData]
}; };
// 添加到处方列表
tcmPrescriptionList.value.push(newPrescription);
} catch (error) { } catch (error) {
console.error('解析医嘱数据失败:', error, '数据项:', item); console.error('解析医嘱数据失败:', error, '数据项:', item);
return item; // 出错时返回原始数据
} }
}); });
@@ -612,11 +622,11 @@ function getListInfo(addNewRow) {
} }
} else { } else {
console.error('获取医嘱列表失败或数据格式错误:', res); console.error('获取医嘱列表失败或数据格式错误:', res);
prescriptionList.value = []; tcmPrescriptionList.value = [];
} }
}).catch(error => { }).catch(error => {
console.error('获取医嘱列表异常:', error); console.error('获取医嘱列表异常:', error);
prescriptionList.value = []; tcmPrescriptionList.value = [];
}); });
tcmDiagnosisList.value = getFromDiagnosis(props.patientInfo.encounterId); tcmDiagnosisList.value = getFromDiagnosis(props.patientInfo.encounterId);
@@ -769,7 +779,8 @@ function handleDeletePrescriptionClick(prescriptionIndex) {
} }
// 检查是否有已签发的药品 // 检查是否有已签发的药品
const hasChargedItems = prescriptionList.value.some(item => item.statusEnum === 2); const prescription = tcmPrescriptionList.value[prescriptionIndex];
const hasChargedItems = prescription.prescriptionList.some(item => item.statusEnum === 2);
if (hasChargedItems) { if (hasChargedItems) {
proxy.$modal.msgWarning('该处方单已收费,不能删除'); proxy.$modal.msgWarning('该处方单已收费,不能删除');
return; return;
@@ -793,16 +804,18 @@ function isPrescriptionDeletable(prescriptionIndex) {
} }
// 检查是否有已签发的药品 // 检查是否有已签发的药品
const hasChargedItems = prescriptionList.value.some(item => item.statusEnum === 2); const hasChargedItems = tcmPrescriptionList.value.some(item =>
item.prescriptionList && item.prescriptionList.some(med => med.statusEnum === 2)
);
return !hasChargedItems; return !hasChargedItems;
} }
// 计算处方总价 // 计算处方总价
function getPrescriptionTotalPrice(prescriptionIndex) { function getPrescriptionTotalPrice(prescriptionIndex) {
const prescription = prescriptionList.value[prescriptionIndex]; const prescription = tcmPrescriptionList.value[prescriptionIndex];
let totalPrice = 0; let totalPrice = 0;
if (prescription && prescription.prescriptionDetailsList) { if (prescription && prescription.prescriptionList) {
prescription.prescriptionDetailsList.forEach(item => { prescription.prescriptionList.forEach(item => {
// 使用decimal.js确保精度计算 // 使用decimal.js确保精度计算
const quantity = new Decimal(item.minUnitQuantity || 0); const quantity = new Decimal(item.minUnitQuantity || 0);
const unitPrice = new Decimal(item.unitPrice || 0); const unitPrice = new Decimal(item.unitPrice || 0);
@@ -814,9 +827,11 @@ function getPrescriptionTotalPrice(prescriptionIndex) {
// 获取处方中的药品数量 // 获取处方中的药品数量
function getPrescriptionMedicineCount(prescriptionIndex) { function getPrescriptionMedicineCount(prescriptionIndex) {
// 这里需要根据实际的业务逻辑来计算 const prescription = tcmPrescriptionList.value[prescriptionIndex];
// 假设每个处方对应一组药品,这里简化处理 if (prescription && prescription.prescriptionList) {
return prescriptionList.value.filter(item => item.statusEnum !== 2).length; return prescription.prescriptionList.length;
}
return 0;
} }
/** /**
@@ -959,7 +974,9 @@ function handleDelete(pIndex) {
prescription.expandOrder = []; prescription.expandOrder = [];
prescription.isAdding = false; prescription.isAdding = false;
adviceQueryParams.value.adviceType = undefined; adviceQueryParams.value.adviceType = undefined;
groupMarkers.value = getGroupMarkers(prescriptionList.value); // 删除行会出现组号混乱的情况,所以这里重新更新标记 // 删除行会出现组号混乱的情况,所以这里重新更新标记
const allPrescriptions = tcmPrescriptionList.value.flatMap(p => p.prescriptionList);
groupMarkers.value = getGroupMarkers(allPrescriptions);
} }
@@ -1115,10 +1132,21 @@ function handleSaveSign(row, index) {
function handleSaveBatch() { function handleSaveBatch() {
let saveList = prescriptionList.value // 收集所有需要保存的处方项目
.filter((item) => { let saveList = [];
return item.statusEnum == 1;
}) // 遍历所有处方
for (const prescription of tcmPrescriptionList.value) {
if (prescription.prescriptionList) {
// 检查处方是否有必填的付数
if (!prescription.chineseHerbsDoseQuantity || prescription.chineseHerbsDoseQuantity == 0) {
proxy.$modal.msgWarning('请输入付数');
return;
}
// 收集该处方下需要保存的项目
const itemsToSave = prescription.prescriptionList
.filter((item) => item.statusEnum == 1)
.map((item, index) => { .map((item, index) => {
return { return {
...item, ...item,
@@ -1130,29 +1158,36 @@ function handleSaveBatch() {
patientId: props.patientInfo.patientId, patientId: props.patientInfo.patientId,
requestId: item.requestId, requestId: item.requestId,
groupId: item.groupId ? item.groupId : timestamp.toString(), groupId: item.groupId ? item.groupId : timestamp.toString(),
chineseHerbsDoseQuantity: prescription.chineseHerbsDoseQuantity, chineseHerbsDoseQuantity: prescription.chineseHerbsDoseQuantity,
dbOpType: item.requestId ? '2' : '1', dbOpType: item.requestId ? '2' : '1',
}; };
}); });
// 将项目添加到保存列表
saveList = saveList.concat(itemsToSave);
}
}
// 检查是否有可保存的项目
if (saveList.length == 0) { if (saveList.length == 0) {
proxy.$modal.msgWarning('当前没有可保存医嘱'); proxy.$modal.msgWarning('当前没有可保存医嘱');
return; return;
} }
if (
prescription.chineseHerbsDoseQuantity == undefined || // 保存处方
prescription.chineseHerbsDoseQuantity == 0
) {
proxy.$modal.msgWarning('请输入付数');
return;
}
saveTcmAdvice({ adviceSaveList: saveList }).then((res) => { saveTcmAdvice({ adviceSaveList: saveList }).then((res) => {
if (res.code === 200) { if (res.code === 200) {
proxy.$modal.msgSuccess('保存成功'); proxy.$modal.msgSuccess('保存成功');
getListInfo(true); getListInfo(true);
// 重置所有处方的nextId
tcmPrescriptionList.value.forEach(prescription => {
if (prescription.nextId) {
prescription.nextId = 1; prescription.nextId = 1;
} }
}); });
}
});
} }
// 获取诊断列表 // 获取诊断列表

View File

@@ -3,43 +3,24 @@
<div style="width: 15%; height: 100%; border: 1px solid #eee; border-right: 0"> <div style="width: 15%; height: 100%; border: 1px solid #eee; border-right: 0">
<div style="padding: 10px; border: 1px solid #eee; height: 50px; border-right: 0"> <div style="padding: 10px; border: 1px solid #eee; height: 50px; border-right: 0">
<span>现诊患者</span> <span>现诊患者</span>
<el-badge <el-badge :value="waitCount > 0 ? waitCount : ''" :max="10"
:value="waitCount > 0 ? waitCount : ''" style="float: right; color: #409eff; cursor: pointer; margin-right: 10px">
:max="10"
style="float: right; color: #409eff; cursor: pointer; margin-right: 10px"
>
<span @click="openDrawer"> 患者队列 </span> <span @click="openDrawer"> 患者队列 </span>
</el-badge> </el-badge>
</div> </div>
<div style="width: 100%; padding: 10px"> <div style="width: 100%; padding: 10px">
<el-input <el-input v-model="queryParams.searchKey" placeholder="请输入患者名" clearable
v-model="queryParams.searchKey" style="width: 100%; margin-bottom: 10px" @keyup.enter="getPatientList">
placeholder="请输入患者名"
clearable
style="width: 100%; margin-bottom: 10px"
@keyup.enter="getPatientList"
>
<template #append> <template #append>
<el-button icon="Search" @click="getPatientList" /> <el-button icon="Search" @click="getPatientList" />
</template> </template>
</el-input> </el-input>
<el-date-picker <el-date-picker v-model="registerTime" @change="handleTimeChange" type="daterange"
v-model="registerTime" style="width: 100%; margin-bottom: 10px" :clearable="false" placeholder="挂号时间" format="YYYY-MM-DD"
@change="handleTimeChange" value-format="YYYY-MM-DD" />
type="date"
style="width: 100%; margin-bottom: 10px"
:clearable="false"
placeholder="挂号时间"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
/>
<el-scrollbar height="700px"> <el-scrollbar height="700px">
<div <div v-for="(item, index) in patientList" :class="item.active ? 'patient-card actived' : 'patient-card'"
v-for="(item, index) in patientList" :key="item.id" @click="handleCardClick(item, index)">
:class="item.active ? 'patient-card actived' : 'patient-card'"
:key="item.id"
@click="handleCardClick(item, index)"
>
<div class="main-info-container"> <div class="main-info-container">
<!-- <el-avatar <!-- <el-avatar
:size="30" :size="30"
@@ -78,8 +59,8 @@
</div> </div>
<div class="disabled-wrapper" style="width: 85%; border: 1px solid #eee; position: relative"> <div class="disabled-wrapper" style="width: 85%; border: 1px solid #eee; position: relative">
<div style="padding: 10px; border: 1px solid #eee; height: 50px; border-left: 0"> <div style="padding: 10px; border: 1px solid #eee; height: 50px; border-left: 0">
<el-descriptions :column="5" class="patient-info-descriptions"> <el-descriptions :column="4">
<el-descriptions-item label="患者信息:" width="420"> <el-descriptions-item label="患者信息:" width="150">
{{ {{
Object.keys(patientInfo).length !== 0 Object.keys(patientInfo).length !== 0
? patientInfo.patientName + ? patientInfo.patientName +
@@ -88,53 +69,19 @@
' / ' + ' / ' +
patientInfo.genderEnum_enumText + patientInfo.genderEnum_enumText +
' / ' + ' / ' +
patientInfo.contractName + patientInfo.contractName
'/' +
patientInfo.phone
: '-' : '-'
}} }}
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="挂号时间:" width="300"> <el-descriptions-item label="挂号时间:" width="150">
{{ Object.keys(patientInfo).length !== 0 ? formatDate(patientInfo.registerTime) : '-' }} {{ Object.keys(patientInfo).length !== 0 ? formatDate(patientInfo.registerTime) : '-' }}
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="医生:" width="250">
{{ userStore.nickName }}
</el-descriptions-item>
<el-descriptions-item label="" width="300">
<el-button type="primary" plain @click.stop="handleFinish(patientInfo.encounterId)">
完诊
</el-button>
<el-button type="primary" plain @click.stop="handleLeave(patientInfo.encounterId)">
暂离
</el-button>
<el-button type="primary" plain @click.stop="handleRefund(patientInfo.encounterId)">
退费
</el-button>
<el-button
type="primary"
plain
@click.stop="getEnPrescription(patientInfo.encounterId)"
>
处方单
</el-button>
<el-button
type="primary"
plain
@click.stop="
() => {
openDialog = true;
}
"
>
办理住院
</el-button>
</el-descriptions-item>
<el-descriptions-item label="医生:" width="150">{{ <el-descriptions-item label="医生:" width="150">{{
userStore.name userStore.name
}}</el-descriptions-item> }}</el-descriptions-item>
<el-descriptions-item label="" width="350"> <el-descriptions-item label="" width="350">
<!-- 初诊 / 复诊 按钮 --> <!-- 初诊 / 复诊 按钮 -->
<el-radio v-model="visitType" label="FIRST" :disabled="visitTypeDisabled">初诊</el-radio> <el-radio v-model="visitType" label="FIRST" :disabled="visitTypeDisabled">初诊</el-radio>
<el-radio v-model="visitType" label="FOLLOW_UP" :disabled="visitTypeDisabled">复诊</el-radio> <el-radio v-model="visitType" label="FOLLOW_UP" :disabled="visitTypeDisabled">复诊</el-radio>
<!-- 原有按钮 --> <!-- 原有按钮 -->
@@ -147,84 +94,44 @@
<el-button type="primary" plain @click.stop="handleRefund(patientInfo.encounterId)"> <el-button type="primary" plain @click.stop="handleRefund(patientInfo.encounterId)">
退费 退费
</el-button> </el-button>
<el-button <el-button type="primary" plain @click.stop="getEnPrescription(patientInfo.encounterId)">
type="primary"
plain
@click.stop="getEnPrescription(patientInfo.encounterId)"
>
处方单 处方单
</el-button> </el-button>
<el-button <el-button type="primary" plain @click.stop="openDialog = true">
type="primary"
plain
@click.stop="openDialog = true"
>
办理住院 办理住院
</el-button> </el-button>
<el-button <el-button type="primary" plain @click.stop="handleCancelEncounter">
type="primary"
plain
@click.stop="handleCancelEncounter"
>
取消接诊 取消接诊
</el-button> </el-button>
</el-descriptions-item> </el-descriptions-item>
</el-descriptions> </el-descriptions>
</div> </div>
<div style="padding: 10px"> <div style="padding: 10px">
<el-tabs <el-tabs type="card" style="width: 100%; height: 100%" v-loading="loading" v-model="activeTab"
type="card" @tab-change="handleClick(activeTab)">
style="width: 100%; height: 100%"
v-loading="loading"
v-model="activeTab"
@tab-change="handleClick(activeTab)"
>
<el-tab-pane label="门诊病历" name="hospitalizationEmr">
<hospitalizationEmr
:patientInfo="patientInfo"
:activeTab="activeTab"
@emrSaved="handleEmrSaved"
/>
</el-tab-pane>
<el-tab-pane label="病历" name="emr"> <el-tab-pane label="病历" name="emr">
<Emr <Emr :patientInfo="patientInfo" ref="emrRef" @save="
:patientInfo="patientInfo"
ref="emrRef"
@save="
(value) => { (value) => {
saveStatus = value; saveStatus = value;
} }
" " :visitType="visitType" :firstVisitDate="firstVisitDate" />
:visitType="visitType"
:firstVisitDate="firstVisitDate"
/>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="诊断" name="diagnosis"> <el-tab-pane label="诊断" name="diagnosis">
<Diagnosis <Diagnosis :patientInfo="patientInfo" ref="diagnosisRef" @diagnosisSave="
:patientInfo="patientInfo"
ref="diagnosisRef"
@diagnosisSave="
(value) => { (value) => {
saveStatus = value; saveStatus = value;
} }
" " />
/>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="医嘱" name="prescription"> <el-tab-pane label="医嘱" name="prescription">
<prescriptionlist <prescriptionlist :patientInfo="patientInfo" ref="prescriptionRef" :activeTab="activeTab" />
:patientInfo="patientInfo"
ref="prescriptionRef"
:activeTab="activeTab"
:outpatientEmrSaved="outpatientEmrSaved"
/>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="中医" name="tcm"> <el-tab-pane label="中医" name="tcm">
<tcmAdvice :patientInfo="patientInfo" ref="tcmRef" /> <tcmAdvice :patientInfo="patientInfo" ref="tcmRef" />
</el-tab-pane> </el-tab-pane>
<!-- <el-tab-pane label="电子处方" name="eprescription"> <el-tab-pane label="电子处方" name="eprescription">
<eprescriptionlist :patientInfo="patientInfo" ref="eprescriptionRef" /> <eprescriptionlist :patientInfo="patientInfo" ref="eprescriptionRef" />
</el-tab-pane> </el-tab-pane>
-->
</el-tabs> </el-tabs>
<div class="overlay" v-if="disabled"></div> <div class="overlay" v-if="disabled"></div>
</div> </div>
@@ -232,27 +139,15 @@
<el-drawer v-model="drawer" title="患者队列" direction="ltr" @open="handleOpen"> <el-drawer v-model="drawer" title="患者队列" direction="ltr" @open="handleOpen">
<PatientList ref="patientDrawerRef" @toCurrent="handleReceive" /> <PatientList ref="patientDrawerRef" @toCurrent="handleReceive" />
</el-drawer> </el-drawer>
<RefundListDialog <RefundListDialog :open="openRefundListDialog" :encounterId="currentEncounterId"
:open="openRefundListDialog" @close="openRefundListDialog = false" />
:encounterId="currentEncounterId" <HospitalizationDialog :open="openDialog" :patientInfo="patientInfo" :encounterId="currentEncounterId"
@close="openRefundListDialog = false" @close="openDialog = false" />
@refresh="() => prescriptionRef.getListInfo()" <PrescriptionInfo :open="openPrescriptionDialog" :precriptionInfo="prescriptionInfo"
/> @close="openPrescriptionDialog = false" />
<HospitalizationDialog
:open="openDialog"
:patientInfo="patientInfo"
:encounterId="currentEncounterId"
@close="openDialog = false"
/>
<PrescriptionInfo
:open="openPrescriptionDialog"
:precriptionInfo="prescriptionInfo"
@close="openPrescriptionDialog = false"
/>
</div> </div>
</template> </template>
<script setup> <script setup>
import hospitalizationEmr from './components/hospitalizationEmr/index.vue';
import Emr from './components/emr/emr.vue'; import Emr from './components/emr/emr.vue';
import { import {
getList, getList,
@@ -267,14 +162,13 @@ import RefundListDialog from './components/prescription/refundListDialog.vue';
import PatientList from './components/patientList.vue'; import PatientList from './components/patientList.vue';
import Diagnosis from './components/diagnosis/diagnosis.vue'; import Diagnosis from './components/diagnosis/diagnosis.vue';
import PrescriptionInfo from './components/prescription/prescriptionInfo.vue'; import PrescriptionInfo from './components/prescription/prescriptionInfo.vue';
// import eprescriptionlist from './components/eprescriptionlist.vue'; import eprescriptionlist from './components/eprescriptionlist.vue';
import HospitalizationDialog from './components/hospitalizationDialog.vue'; import HospitalizationDialog from './components/hospitalizationDialog.vue';
import tcmAdvice from './components/tcm/tcmAdvice.vue'; import tcmAdvice from './components/tcm/tcmAdvice.vue';
import { formatDate, formatDateStr } from '@/utils/index'; import { formatDate, formatDateStr } from '@/utils/index';
import useUserStore from '@/store/modules/user'; import useUserStore from '@/store/modules/user';
import { nextTick } from 'vue'; import { nextTick } from 'vue';
import { onBeforeRouteLeave } from 'vue-router'; import { onBeforeRouteLeave } from 'vue-router';
import { updatePatientInfo } from './components/store/patient.js';
// // 监听路由离开事件 // // 监听路由离开事件
// onBeforeRouteLeave((to, from, next) => { // onBeforeRouteLeave((to, from, next) => {
@@ -303,18 +197,15 @@ const openRefundListDialog = ref(false);
const openDialog = ref(false); const openDialog = ref(false);
const openPrescriptionDialog = ref(false); const openPrescriptionDialog = ref(false);
const saveStatus = ref(false); const saveStatus = ref(false);
const outpatientEmrSaved = ref(false); // 门诊病历保存状态
const currentEncounterId = ref(''); const currentEncounterId = ref('');
const emits = defineEmits(['click']); const emits = defineEmits(['click']);
// const activeTab = ref('emr'); const activeTab = ref('emr');
const activeTab = ref('hospitalizationEmr');
const patientList = ref([]); const patientList = ref([]);
const patientInfo = ref({}); const patientInfo = ref({});
const visitTypeDisabled = ref(false); const visitTypeDisabled = ref(false);
const prescriptionInfo = ref([]); const prescriptionInfo = ref([]);
const registerTime = ref(formatDate(new Date())); const registerTime = ref([formatDate(new Date()), formatDate(new Date())]);
const patientDrawerRef = ref(); const patientDrawerRef = ref();
const prescriptionRef = ref(); const prescriptionRef = ref();
const tcmRef = ref(); const tcmRef = ref();
@@ -328,41 +219,12 @@ const firstVisitDate = ref('');
const disabled = computed(() => { const disabled = computed(() => {
return Object.keys(patientInfo.value).length === 0; return Object.keys(patientInfo.value).length === 0;
}); });
const shortcuts = [
{
text: '今天',
value: new Date(),
},
{
text: '昨天',
value: () => {
const date = new Date();
date.setDate(date.getDate() - 1);
return date;
},
},
{
text: '三天内',
value: () => {
const date = new Date();
date.setDate(date.getDate() - 3);
return date;
},
},
{
text: '一周内',
value: () => {
const date = new Date();
date.setDate(date.getDate() - 7);
return date;
},
},
];
// const eprescriptionRef = ref(); const eprescriptionRef = ref();
onMounted(() => { onMounted(() => {
getWaitPatient(); getWaitPatient();
}); });
getPatientList(); getPatientList();
// 获取现诊患者列表 // 获取现诊患者列表
function getPatientList() { function getPatientList() {
@@ -380,7 +242,7 @@ function setVisitType(type) {
visitType.value = type; visitType.value = type;
} }
function checkPatientHistory(patient) { function checkPatientHistory(patient) {
// 重置状态 // 重置状态
visitTypeDisabled.value = false; visitTypeDisabled.value = false;
firstVisitDate.value = ''; firstVisitDate.value = '';
@@ -451,9 +313,9 @@ function handleClick(tab) {
case 'tcm': case 'tcm':
tcmRef.value.getDiagnosisInfo(); tcmRef.value.getDiagnosisInfo();
break; break;
// case 'eprescription': case 'eprescription':
// eprescriptionRef.value.getList(); eprescriptionRef.value.getList();
// break; break;
} }
// if (tab != 'emr') { // if (tab != 'emr') {
// if (!saveStatus.value) { // if (!saveStatus.value) {
@@ -471,11 +333,6 @@ function handleClick(tab) {
// 查看本次就诊处方单从医嘱Tab页获取已开立的处方单信息 // 查看本次就诊处方单从医嘱Tab页获取已开立的处方单信息
function getEnPrescription(encounterId) { function getEnPrescription(encounterId) {
getEnPrescriptionInfo({ encounterId: encounterId }).then((res) => {
console.log('处方单 res', res);
prescriptionInfo.value = res.data.records;
openPrescriptionDialog.value = true;
});
// 检查是否有选中的患者 // 检查是否有选中的患者
if (!patientInfo.value || !patientInfo.value.encounterId) { if (!patientInfo.value || !patientInfo.value.encounterId) {
proxy.$modal.msgWarning('请先选择患者'); proxy.$modal.msgWarning('请先选择患者');
@@ -553,9 +410,6 @@ function handleCardClick(item, index) {
patient.active = patient.encounterId === item.encounterId; patient.active = patient.encounterId === item.encounterId;
}); });
patientInfo.value = item; patientInfo.value = item;
// 将患者信息保存到store中供hospitalizationEmr组件使用
updatePatientInfo(item);
activeTab.value = 'hospitalizationEmr';
// 优先使用数据库中保存的初复诊值 // 优先使用数据库中保存的初复诊值
if (item.visitType) { if (item.visitType) {
@@ -572,11 +426,17 @@ function handleCardClick(item, index) {
} }
activeTab.value = 'emr'; activeTab.value = 'emr';
nextTick(() => { nextTick(() => {
prescriptionRef.value.getListInfo(); // 确保所有组件引用都已初始化
tcmRef.value.getListInfo(); if (prescriptionRef.value) prescriptionRef.value.getListInfo();
diagnosisRef.value.getList(); if (tcmRef.value) tcmRef.value.getListInfo();
// eprescriptionRef.value.getList(); if (diagnosisRef.value) diagnosisRef.value.getList();
if (eprescriptionRef.value) eprescriptionRef.value.getList();
if (emrRef.value) {
emrRef.value.getDetail(item.encounterId); emrRef.value.getDetail(item.encounterId);
} else {
console.error('emr组件未正确初始化');
proxy.$modal.msgError('病历组件加载失败,请刷新页面重试');
}
setTimeout(() => { setTimeout(() => {
loading.value = false; loading.value = false;
}, 200); }, 200);
@@ -606,8 +466,8 @@ function handleFinish(encounterId) {
} }
function handleTimeChange(value) { function handleTimeChange(value) {
queryParams.value.registerTimeSTime = value + ' 00:00:00'; queryParams.value.registerTimeSTime = value[0] + ' 00:00:00';
queryParams.value.registerTimeETime = value + ' 23:59:59'; queryParams.value.registerTimeETime = value[1] + ' 23:59:59';
getPatientList(); getPatientList();
} }
@@ -620,17 +480,12 @@ function handleReceive(row) {
getWaitPatient(); getWaitPatient();
} }
// 处理门诊病历保存成功事件
function handleEmrSaved(isSaved) {
outpatientEmrSaved.value = isSaved;
}
function openDrawer() { function openDrawer() {
drawer.value = true; drawer.value = true;
} }
function handleCancelEncounter(){ function handleCancelEncounter() {
proxy.$modal.confirm('您确定要取消病人本次的就诊记录吗?','提示信息',{ proxy.$modal.confirm('您确定要取消病人本次的就诊记录吗?', '提示信息', {
confirmButtonText: '是(Y)', confirmButtonText: '是(Y)',
cancelButtonText: '否(N)', cancelButtonText: '否(N)',
type: 'warning' type: 'warning'
@@ -643,7 +498,7 @@ function handleCancelEncounter(){
getPatientList(); getPatientList();
} }
}).catch((error) => { }).catch((error) => {
proxy.$modal.confirm('该病人本次就诊已经有业务产生,不能取消接诊!','提示信息',{ proxy.$modal.confirm('该病人本次就诊已经有业务产生,不能取消接诊!', '提示信息', {
confirmButtonText: '是(Y)', confirmButtonText: '是(Y)',
type: 'warning' type: 'warning'
}); });
@@ -655,16 +510,6 @@ function handleCancelEncounter(){
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
// 患者信息
.patient-info-descriptions {
:deep(.el-descriptions__label) {
font-size: 16px !important;
}
:deep(.el-descriptions__content) {
font-size: 16px !important;
}
}
.patient-card { .patient-card {
width: 100%; width: 100%;
overflow: hidden; overflow: hidden;
@@ -817,6 +662,7 @@ function handleCancelEncounter(){
} }
} }
} }
:deep(.el-tabs__header) { :deep(.el-tabs__header) {
padding: 0; padding: 0;
position: relative; position: relative;
@@ -826,19 +672,23 @@ function handleCancelEncounter(){
:deep(.el-drawer__header) { :deep(.el-drawer__header) {
margin-bottom: 15px !important; margin-bottom: 15px !important;
} }
:deep(.el-drawer__body) { :deep(.el-drawer__body) {
padding: 10px !important; padding: 10px !important;
} }
.el-badge { .el-badge {
--el-badge-padding: 6px; --el-badge-padding: 6px;
} }
.disabled-wrapper .overlay { .disabled-wrapper .overlay {
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
z-index: 999; /* 确保覆盖在内容上方 */ z-index: 999;
/* 确保覆盖在内容上方 */
cursor: not-allowed; cursor: not-allowed;
} }
</style> </style>

View File

@@ -85,7 +85,6 @@
</div> </div>
</template> </template>
<script setup lang='ts'> <script setup lang='ts'>
import { is } from 'core-js/core/object'
import { getCurrentInstance, onBeforeMount, onMounted, reactive,ref } from 'vue' import { getCurrentInstance, onBeforeMount, onMounted, reactive,ref } from 'vue'
// const { proxy } = getCurrentInstance(); // const { proxy } = getCurrentInstance();
const emits = defineEmits([]) const emits = defineEmits([])

View File

@@ -219,11 +219,11 @@ function getExpirationWarningCount() {
let chartInstance = null; let chartInstance = null;
onActivated(() => { onActivated(() => {
getExpirationWarningCount(); // getExpirationWarningCount();
}) })
onMounted(() => { onMounted(() => {
getExpirationWarningCount(); // getExpirationWarningCount();
const ctx = document.getElementById('statsChart'); const ctx = document.getElementById('statsChart');
if (!ctx) return; if (!ctx) return;

View File

@@ -3,7 +3,8 @@
* @Date: 2025-09-05 22:32:17 * @Date: 2025-09-05 22:32:17
* @Description: 申请单 检验检查输血手术 * @Description: 申请单 检验检查输血手术
--> -->
<template> <template>
<div>
<div class="applicationForm-bottom-btn"> <div class="applicationForm-bottom-btn">
<el-button-group> <el-button-group>
<el-button <el-button
@@ -52,13 +53,14 @@
</div> </div>
</template> </template>
</el-dialog> </el-dialog>
</template> </div>
</template>
<script setup> <script setup>
import { getCurrentInstance, onBeforeMount, onMounted, reactive, ref, computed } from 'vue'; import { getCurrentInstance, onBeforeMount, onMounted, reactive, ref, computed } from 'vue';
import BloodTransfusion from './bloodTransfusion'; import BloodTransfusion from './bloodTransfusion';
import { patientInfo } from '../../../store/patient.js'; import { patientInfo } from '../../../store/patient.js';
import Surgery from './surgery.vue'; import Surgery from './surgery.vue';
import laboratoryTests from './laboratoryTests.vue'; import LaboratoryTests from './laboratoryTests.vue';
import MedicalExaminations from './medicalExaminations.vue'; import MedicalExaminations from './medicalExaminations.vue';
const { proxy } = getCurrentInstance(); const { proxy } = getCurrentInstance();
const emits = defineEmits([]); const emits = defineEmits([]);

View File

@@ -234,7 +234,8 @@ onMounted(() => {
} }
// 获取医疗机构列表 // 获取医疗机构列表
getUserBindTenantList().then((res) => { if (loginForm.value.username) {
getUserBindTenantList(loginForm.value.username).then((res) => {
tenantOptions.value = res.data.map(item => ({ tenantOptions.value = res.data.map(item => ({
label: item.tenantName, label: item.tenantName,
value: item.id value: item.id
@@ -245,6 +246,7 @@ onMounted(() => {
currentTenantName.value = tenantOptions.value[0].label; currentTenantName.value = tenantOptions.value[0].label;
} }
}); });
}
}); });
function handleLogin() { function handleLogin() {
@@ -476,7 +478,10 @@ function handleUserName(value) {
//getCode(); //getCode();
getCookie(); getCookie();
getTenantList(loginForm.value.username); // 只有当 username 存在时才获取租户列表
if (loginForm.value.username) {
getTenantList(loginForm.value.username);
}
</script> </script>
<style> <style>

View File

@@ -49,13 +49,17 @@
</div> </div>
<div class="filter-item"> <div class="filter-item">
<label>科室</label> <label>科室</label>
<select> <el-tree-select
<option value="">请选择科室</option> placeholder="请选择科室"
<option value="内科">内科</option> :data="departments"
<option value="儿科">儿科</option> :props="{
<option value="外科">外科</option> value: 'name',
<option value="妇科">妇科</option> label: 'name',
</select> children: 'children'
}"
value-key="name"
style="width: 100%;"
/>
</div> </div>
<div class="filter-item"> <div class="filter-item">
<label>用户</label> <label>用户</label>
@@ -140,9 +144,10 @@
</template> </template>
<script setup> <script setup>
import { ref, computed } from 'vue'; import { ref, reactive, computed, onMounted } from 'vue';
import { useRouter } from 'vue-router'; import { useRouter, useRoute } from 'vue-router';
import { Edit, View, Delete } from '@element-plus/icons-vue'; import { Edit, View, Delete } from '@element-plus/icons-vue';
import { getLocationTree } from '@/views/charge/outpatientregistration/components/outpatientregistration';
// 创建路由实例 // 创建路由实例
const router = useRouter(); const router = useRouter();
@@ -150,6 +155,46 @@ const router = useRouter();
// 侧边栏状态 // 侧边栏状态
const sidebarActive = ref(false); const sidebarActive = ref(false);
// 科室数据
const departments = ref([]);
// 获取科室数据 - 与门诊挂号页面保持一致
function getDepartmentList() {
console.log('调用getLocationTree API...');
getLocationTree().then((response) => {
console.log('getLocationTree API完整返回:', response);
console.log('getLocationTree API数据结构:', JSON.stringify(response.data, null, 2));
// 检查数据结构并转换为适合el-tree-select的格式
if (Array.isArray(response.data)) {
// 直接使用数组数据
departments.value = response.data;
} else if (response.data && response.data.records) {
// 处理分页格式数据
departments.value = response.data.records;
} else if (response.data && response.data.rows) {
// 处理另一种分页格式数据
departments.value = response.data.rows;
} else {
console.error('API返回数据格式不符合预期:', response.data);
departments.value = [];
}
console.log('最终科室数据:', JSON.stringify(departments.value, null, 2));
}).catch((error) => {
console.error('获取科室数据失败:', error);
departments.value = [];
});
}
// 获取科室数据 - 与门诊挂号页面保持一致,在组件初始化时直接调用
getDepartmentList();
// 初始化数据
onMounted(() => {
// 其他初始化逻辑
});
// 表格数据 // 表格数据
const tableData = ref([ const tableData = ref([
{id: 2348, hospital: '演示医院', date: '2025-11-17', name: '血脂333', type: '检验套餐', level: '全院套餐', dept: '', user: '', amount: 40.00, fee: 0.00, total: 40.00, combined: '否', display: '是', enabled: '是', operator: '徐斌'}, {id: 2348, hospital: '演示医院', date: '2025-11-17', name: '血脂333', type: '检验套餐', level: '全院套餐', dept: '', user: '', amount: 40.00, fee: 0.00, total: 40.00, combined: '否', display: '是', enabled: '是', operator: '徐斌'},

File diff suppressed because it is too large Load Diff

View File

@@ -16,97 +16,147 @@
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="挂号处理" name="tab3"> <el-tab-pane label="挂号处理" name="tab3">
<el-form ref="formRef" :model="formData" label-width="120px" class="config-form"> <el-form ref="formRef" :model="formData" label-width="150px" class="config-form compact-form">
<!-- 第一行 --> <!-- 第一行 -->
<div class="form-row"> <div class="form-row">
<el-form-item label="病历本费用(元)" prop="medicalRecordFee" style="margin-right: 20px;"> <el-form-item label="病历本费用(元)" prop="medicalRecordFee">
<el-input v-model="formData.medicalRecordFee" style="width: 180px" /> <el-input-number v-model="formData.medicalRecordFee" style="width: 150px" :controls-position="'right'" :step="1" :min="0" />
</el-form-item> </el-form-item>
<el-form-item style="margin-left: 20px;"> <el-form-item label="" prop="medicalRecordFlag" checkbox-label>
<el-checkbox v-model="formData.medicalRecordFlag">病历费入账标志</el-checkbox> <template #label>
<div class="checkbox-label-container">
<el-checkbox v-model="formData.medicalRecordFlag" style="margin-right: 8px;" />
<span>病历费入账标志</span>
</div>
</template>
</el-form-item> </el-form-item>
</div> </div>
<!-- 第二行 --> <!-- 第二行 -->
<div class="form-row"> <div class="form-row">
<el-form-item label="就诊卡费(元)" prop="patientCardFee" style="margin-right: 20px;"> <el-form-item label="就诊卡费(元)" prop="patientCardFee">
<el-input v-model="formData.patientCardFee" style="width: 180px" /> <el-input-number v-model="formData.patientCardFee" style="width: 150px" :controls-position="'right'" :step="1" :min="0" />
</el-form-item> </el-form-item>
<el-form-item style="margin-left: 20px;"> <el-form-item label="" prop="isNightShift" checkbox-label>
<el-checkbox v-model="formData.isNightShift">是否启用晚班</el-checkbox> <template #label>
<div class="checkbox-label-container">
<el-checkbox v-model="formData.isNightShift" style="margin-right: 8px;" />
<span>是否启用晚班</span>
</div>
</template>
</el-form-item> </el-form-item>
</div> </div>
<!-- 第三行 --> <!-- 第三行 -->
<div class="form-row"> <div class="form-row">
<el-form-item style="margin-right: 40px;"> <el-form-item label="" prop="patientCardFlag" checkbox-label>
<el-checkbox v-model="formData.patientCardFlag">就诊卡记账标志</el-checkbox> <template #label>
<div class="checkbox-label-container">
<el-checkbox v-model="formData.patientCardFlag" style="margin-right: 8px;" />
<span>就诊卡记账标志</span>
</div>
</template>
</el-form-item> </el-form-item>
<el-form-item label="上午接诊起始时间" prop="morningStartTime" style="width: 300px; white-space: nowrap;"> <el-form-item label="上午接诊起始时间" prop="morningStartTime">
<el-input v-model="formData.morningStartTime" style="width: 120px" /> <el-input v-model="formData.morningStartTime" style="width: 150px" />
</el-form-item> </el-form-item>
</div> </div>
<!-- 第四行 --> <!-- 第四行 -->
<div class="form-row"> <div class="form-row">
<el-form-item style="margin-right: 40px;"> <el-form-item label="" prop="autoGenerateOutpatientNo" checkbox-label>
<el-checkbox v-model="formData.autoGenerateOutpatientNo">自动产生门诊号</el-checkbox> <template #label>
<div class="checkbox-label-container">
<el-checkbox v-model="formData.autoGenerateOutpatientNo" style="margin-right: 8px;" />
<span>自动产生门诊号</span>
</div>
</template>
</el-form-item> </el-form-item>
<el-form-item style="margin-right: 40px;"> <el-form-item label="" prop="allowModifyOutpatientNo" checkbox-label>
<el-checkbox v-model="formData.allowModifyOutpatientNo">建档时是否允许修改门诊号</el-checkbox> <template #label>
<div class="checkbox-label-container">
<el-checkbox v-model="formData.allowModifyOutpatientNo" style="margin-right: 8px;" />
<span>允许修改门诊号</span>
</div>
</template>
</el-form-item> </el-form-item>
</div> </div>
<!-- 第五行 --> <!-- 第五行 -->
<div class="form-row"> <div class="form-row">
<el-form-item label="下午起始时间" prop="afternoonStartTime" style="margin-right: 40px;"> <el-form-item label="下午起始时间" prop="afternoonStartTime">
<el-input v-model="formData.afternoonStartTime" style="width: 120px" /> <el-input v-model="formData.afternoonStartTime" style="width: 150px" />
</el-form-item> </el-form-item>
<el-form-item label="晚上起始时间" prop="eveningStartTime"> <el-form-item label="晚上起始时间" prop="eveningStartTime">
<el-input v-model="formData.eveningStartTime" style="width: 120px" /> <el-input v-model="formData.eveningStartTime" style="width: 150px" />
</el-form-item> </el-form-item>
</div> </div>
<!-- 第六行 --> <!-- 第六行 -->
<div class="form-row"> <div class="form-row">
<el-form-item label="挂号有效期" prop="registrationValidity" style="margin-right: 40px;"> <el-form-item label="挂号有效期" prop="registrationValidity">
<el-input v-model="formData.registrationValidity" style="width: 120px" /> <el-input-number v-model="formData.registrationValidity" style="width: 150px" :controls-position="'right'" :step="1" :min="0" />
</el-form-item> </el-form-item>
<el-form-item label="挂号单据模式" prop="registrationDocumentMode"> <el-form-item label="挂号单据模式" prop="registrationDocumentMode">
<el-select v-model="formData.registrationDocumentMode" style="width: 150px"> <el-select v-model="formData.registrationDocumentMode" style="width: 150px">
<el-option label="使用发票" value="使用发票" /> <el-option label="使用发票" value="使用发票" />
<el-option label="其他模式" value="其他模式" /> <el-option label="普通单据" value="其他模式" />
</el-select> </el-select>
</el-form-item> </el-form-item>
</div> </div>
<!-- 第七行 --> <!-- 第七行 -->
<div class="form-row"> <div class="form-row">
<el-form-item style="margin-right: 40px;"> <el-form-item label="" prop="exemptFlag" checkbox-label>
<el-checkbox v-model="formData.exemptFlag">减免标志</el-checkbox> <template #label>
<div class="checkbox-label-container">
<el-checkbox v-model="formData.exemptFlag" style="margin-right: 8px;" />
<span>减免标志</span>
</div>
</template>
</el-form-item> </el-form-item>
<el-form-item style="margin-right: 40px;"> <el-form-item label="" prop="consultationFlag" checkbox-label>
<el-checkbox v-model="formData.consultationFlag">义诊标志</el-checkbox> <template #label>
<div class="checkbox-label-container">
<el-checkbox v-model="formData.consultationFlag" style="margin-right: 8px;" />
<span>义诊标志</span>
</div>
</template>
</el-form-item> </el-form-item>
<el-form-item style="margin-right: 40px;"> <el-form-item label="" prop="enableHolidayFeeFloat" checkbox-label>
<el-checkbox v-model="formData.enableHolidayFeeFloat">启用法定节假日挂号费浮动</el-checkbox> <template #label>
<div class="checkbox-label-container">
<el-checkbox v-model="formData.enableHolidayFeeFloat" style="margin-right: 8px;" />
<span>节假日费浮动</span>
</div>
</template>
</el-form-item> </el-form-item>
</div> </div>
<!-- 第八行 --> <!-- 第八行 -->
<div class="form-row"> <div class="form-row">
<el-form-item label="监护人规定年龄" prop="guardianAge" style="margin-right: 40px;"> <el-form-item label="监护人规定年龄" prop="guardianAge">
<el-input v-model="formData.guardianAge" style="width: 120px" /> <el-input-number v-model="formData.guardianAge" style="width: 150px" :controls-position="'right'" :step="1" :min="0" />
</el-form-item> </el-form-item>
<el-form-item> <el-form-item label="" prop="enableDoubleScreen" checkbox-label>
<el-checkbox v-model="formData.enableDoubleScreen">门诊挂号启用双屏</el-checkbox> <template #label>
<div class="checkbox-label-container">
<el-checkbox v-model="formData.enableDoubleScreen" style="margin-right: 8px;" />
<span>挂号启用双屏</span>
</div>
</template>
</el-form-item> </el-form-item>
</div> </div>
<!-- 第九行 --> <!-- 第九行 -->
<div class="form-row"> <div class="form-row">
<el-form-item> <el-form-item label="" prop="optionalRegistrationType" checkbox-label>
<el-checkbox v-model="formData.optionalRegistrationType">挂号类型可选择</el-checkbox> <template #label>
<div class="checkbox-label-container">
<el-checkbox v-model="formData.optionalRegistrationType" style="margin-right: 8px;" />
<span>挂号类型可选择</span>
</div>
</template>
</el-form-item> </el-form-item>
</div> </div>
</el-form> </el-form>
@@ -132,10 +182,10 @@
</template> </template>
<script setup> <script setup>
import { ref, reactive } from 'vue'; import { ref, reactive, onMounted } from 'vue';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import { ElMessage } from 'element-plus'; import { ElMessage } from 'element-plus';
import { getConfigKey, addConfig, updateConfig } from '@/api/system/config'; import { listConfig, getConfigKey, addConfig, updateConfig } from '@/api/system/config';
const router = useRouter(); const router = useRouter();
const formRef = ref(null); const formRef = ref(null);
@@ -164,6 +214,61 @@ const formData = reactive({
isPrint: false, isPrint: false,
}); });
// 加载配置数据
const loadConfigData = async (showSuccessMessage = true) => {
try {
// 调用系统配置API获取数据不设置configType过滤条件以获取所有配置
const response = await listConfig({ pageSize: 1000 });
// 处理响应数据,兼容不同的返回格式
let configs = [];
if (response && response.data) {
if (Array.isArray(response.data)) {
configs = response.data;
} else if (response.data.rows && Array.isArray(response.data.rows)) {
configs = response.data.rows;
} else {
console.error('返回数据格式不符合预期:', response);
}
} else if (response && response.rows && Array.isArray(response.rows)) {
configs = response.rows;
} else {
console.error('API返回空响应:', response);
}
console.log('loadConfigData - 获取到的配置列表:', configs);
console.log('loadConfigData - 配置总数:', configs.length);
// 将配置数据映射到表单
if (configs && configs.length > 0) {
configs.forEach(config => {
const { configKey, configValue } = config;
// 处理布尔类型字段
if (configKey in formData) {
if (typeof formData[configKey] === 'boolean') {
formData[configKey] = configValue === '1';
} else {
formData[configKey] = configValue;
}
}
});
}
if (showSuccessMessage) {
ElMessage.success('配置数据加载成功');
}
} catch (error) {
console.error('加载配置数据失败:', error);
ElMessage.warning('无法加载配置数据,使用默认值');
}
};
// 组件挂载时加载数据
onMounted(() => {
loadConfigData();
});
// 默认按钮点击事件 // 默认按钮点击事件
const handleDefault = () => { const handleDefault = () => {
// 重置为默认值 // 重置为默认值
@@ -225,40 +330,88 @@ const handleSave = async () => {
let successCount = 0; let successCount = 0;
let failedParams = []; let failedParams = [];
try {
// 先获取所有配置避免重复调用API
const allConfigsResponse = await listConfig({ pageSize: 1000 });
console.log('handleSave - listConfig返回完整结果:', JSON.stringify(allConfigsResponse));
// 检查返回结果结构
let allConfigs = [];
if (allConfigsResponse.code === 200) {
if (allConfigsResponse.data && Array.isArray(allConfigsResponse.data)) {
allConfigs = allConfigsResponse.data;
} else if (allConfigsResponse.data && allConfigsResponse.data.rows) {
allConfigs = allConfigsResponse.data.rows;
} else if (Array.isArray(allConfigsResponse.rows)) {
allConfigs = allConfigsResponse.rows;
} else if (Array.isArray(allConfigsResponse)) {
allConfigs = allConfigsResponse;
}
}
console.log('handleSave - 最终获取到的所有配置:', allConfigs);
console.log('handleSave - 配置总数:', allConfigs.length);
// 构建配置项映射表,方便快速查找
const configMap = new Map();
allConfigs.forEach(config => {
configMap.set(config.configKey, config);
console.log('handleSave - 添加到映射表:', config.configKey);
});
// 调用系统配置API保存每个参数 // 调用系统配置API保存每个参数
for (const config of configData) { for (const config of configData) {
try { try {
// 先查询是否存在该配置 const existingConfig = configMap.get(config.configKey);
const existingConfig = await getConfigKey(config.configKey, { skipErrorMsg: true });
if (existingConfig.data && existingConfig.data.configId) { console.log(`处理参数: ${config.configName} (${config.configKey})`);
// 如果存在则更新保留原有数据的configId console.log(`现有配置:`, existingConfig);
await updateConfig({ console.log(`要保存的值:`, config.configValue);
if (existingConfig && existingConfig.configId) {
// 如果存在则更新保留原有数据的configId和创建时间
console.log(`更新参数 ${config.configKey}使用configId: ${existingConfig.configId}`);
const updateResult = await updateConfig({
...config, ...config,
configId: existingConfig.data.configId, configId: existingConfig.configId,
createTime: existingConfig.data.createTime, // 保留创建时间 createTime: existingConfig.createTime,
remark: existingConfig.data.remark || '收费系统配置参数' // 保留或设置默认备注 remark: existingConfig.remark || '收费系统配置参数',
configType: existingConfig.configType || 'N'
}); });
console.log(`更新结果:`, updateResult);
} else { } else {
// 如果不存在则新增,添加默认备注 // 如果不存在则新增,添加默认备注
await addConfig({ console.log(`新增参数 ${config.configKey}`);
const addResult = await addConfig({
...config, ...config,
remark: '收费系统配置参数' remark: '收费系统配置参数',
configType: 'N'
}); });
console.log(`新增结果:`, addResult);
} }
successCount++; successCount++;
} catch (paramError) { } catch (paramError) {
console.error(`保存参数 ${config.configName} (${config.configKey}) 失败:`, paramError); console.error(`保存参数 ${config.configName} (${config.configKey}) 失败:`, paramError);
console.error(`错误详情:`, paramError.response || paramError);
failedParams.push(config.configName); failedParams.push(config.configName);
// 继续处理下一个参数,不中断整体流程 // 继续处理下一个参数,不中断整体流程
} }
} }
} catch (error) {
console.error('获取配置列表失败:', error);
ElMessage.error('获取配置列表失败,无法保存参数');
return;
}
// 根据保存结果显示相应消息 // 根据保存结果显示相应消息
if (failedParams.length === 0) { if (failedParams.length === 0) {
ElMessage.success(`所有 ${successCount} 个参数保存成功`); ElMessage.success(`保存成功`);
// 保存成功后重新加载数据,确保页面显示最新配置
loadConfigData(false); // 不显示加载成功消息
} else if (successCount > 0) { } else if (successCount > 0) {
ElMessage.warning(`${successCount} 个参数保存成功,但以下 ${failedParams.length} 个参数保存失败: ${failedParams.join(', ')}`); ElMessage.warning(`${successCount} 个参数保存成功,但以下 ${failedParams.length} 个参数保存失败: ${failedParams.join(', ')}`);
// 部分成功也重新加载数据
loadConfigData(false); // 不显示加载成功消息
} else { } else {
ElMessage.error(`所有参数保存失败,请检查系统配置`); ElMessage.error(`所有参数保存失败,请检查系统配置`);
} }
@@ -300,23 +453,96 @@ const handleClose = () => {
.form-row { .form-row {
display: flex; display: flex;
align-items: center; align-items: center;
margin-bottom: 5px; margin-bottom: 15px;
flex-wrap: wrap; flex-wrap: nowrap; /* 禁止行内元素换行 */
overflow-x: hidden; /* 防止溢出 */
} }
.config-form .el-form-item { .config-form .el-form-item {
margin-bottom: 0; margin-bottom: 0;
margin-right: 0; margin-right: 60px; /* 增加间距 */
min-width: 350px; /* 增加最小宽度 */
display: flex;
align-items: center;
flex-shrink: 0; /* 禁止压缩 */
} }
/* 紧凑表单样式 */
.compact-form {
label-width: 150px !important;
}
.compact-form .el-form-item {
margin-bottom: 10px;
}
/* 所有表单标签的统一样式 */
.config-form .el-form-item__label { .config-form .el-form-item__label {
font-weight: 500; font-weight: 500;
width: 120px; width: 220px !important; /* 足够宽的标签宽度 */
text-align: right;
padding-right: 15px;
white-space: nowrap !important; /* 强制不换行 */
overflow: visible !important; /* 允许内容溢出(确保不截断) */
text-overflow: clip !important; /* 不显示省略号 */
flex-shrink: 0 !important; /* 禁止压缩 */
font-size: 14px !important; /* 统一字体大小 */
line-height: 32px !important; /* 统一行高 */
height: 32px !important; /* 统一高度 */
margin: 0 !important; /* 清除默认边距 */
padding: 0 15px 0 0 !important; /* 统一内边距 */
}
/* 复选框标签样式 */
.compact-form .el-form-item[checkbox-label] .el-form-item__label {
padding-right: 10px;
width: 150px !important;
text-align: right; text-align: right;
} }
.compact-form .el-form-item[checkbox-label] .el-form-item__content {
margin-left: 0 !important;
}
/* 自定义复选框标签容器 */
.checkbox-label-container {
display: flex;
align-items: center;
justify-content: flex-end;
width: 100%;
height: 100%;
}
.checkbox-label-container span {
font-size: 14px;
white-space: nowrap;
}
/* 空标签的样式,用于对齐 */
.config-form .el-form-item__label:empty {
width: 18px !important;
padding-right: 5px !important;
}
.config-form .el-form-item--medium .el-form-item__content { .config-form .el-form-item--medium .el-form-item__content {
line-height: 28px; line-height: 32px;
flex-shrink: 0;
height: 32px;
}
.config-form .el-checkbox {
margin-left: 0;
font-size: 14px;
}
/* 确保输入框与标签对齐 */
.config-form .el-input {
height: 32px;
font-size: 14px;
}
.config-form .el-input__wrapper {
height: 32px;
} }
.tab-content { .tab-content {

View File

@@ -252,11 +252,11 @@ function getList() {
...queryParams.value, ...queryParams.value,
flg: queryParams.value.flg == 1 ? '1' : null, flg: queryParams.value.flg == 1 ? '1' : null,
}; };
getExpirationWarning(params).then((res) => { // getExpirationWarning(params).then((res) => {
loading.value = false; // loading.value = false;
purchaseinventoryList.value = res.data.records; // purchaseinventoryList.value = res.data.records;
total.value = res.data.total; // total.value = res.data.total;
}); // });
} }
/** 搜索按钮操作 */ /** 搜索按钮操作 */

View File

@@ -306,11 +306,12 @@ export function ybRequestFileUp(data) {
}) })
} }
export function getExpirationWarning(query) { export function getExpirationWarning(query) {
return request({ // return request({
url: '/inventory-manage/product/expiration-warning', // url: '/inventory-manage/product/expiration-warning',
method: 'get', // method: 'get',
params: query // params: query
}) // })
return null;
} }
export function getClroptins(query) { export function getClroptins(query) {
return request({ return request({

View File

@@ -0,0 +1,25 @@
// 测试util._extend是否存在
if (typeof process !== 'undefined' && process.versions && process.versions.node) {
try {
const util = require('util');
console.log('util._extend存在吗', typeof util._extend);
if (typeof util._extend === 'function') {
console.log('util._extend是一个函数');
} else {
console.log('util._extend不是一个函数添加兼容实现');
util._extend = function(destination, source) {
for (var key in source) {
if (source.hasOwnProperty(key)) {
destination[key] = source[key];
}
}
return destination;
};
console.log('兼容实现添加成功');
}
} catch (e) {
console.error('util模块加载失败:', e);
}
} else {
console.log('不在Node.js环境中');
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long