Compare commits

23 Commits

Author SHA1 Message Date
46c9787216 修改套餐管理页面操作图标设置 2025-12-05 16:50:37 +08:00
e0a768de2e 新增套餐设置页面中的套餐管理页面并增加相应跳转逻辑 2025-12-05 16:37:34 +08:00
fc7f931728 新增套餐设置页面中的套餐管理页面并增加相应跳转逻辑 2025-12-05 16:34:12 +08:00
qk123
3ccb970a09 维护系统->检查方法、部位导出表格功能OK 2025-12-05 15:54:57 +08:00
ljj
8a9a622aeb 72.系统管理--》基础数据-》科室管理 2025-12-05 13:39:23 +08:00
qk123
29e7f0937b 维护系统->检查方法、部位条件搜索前后端实现 2025-12-04 14:47:39 +08:00
029d534b3c 新增检验项目设置中的检验类型页面并实现相关逻辑 2025-12-04 09:47:34 +08:00
qk123
213723b220 维护系统->检查方法后端接口数据校验修改 2025-12-04 09:33:44 +08:00
qk123
c636e77fd0 维护系统->检查部位前端接口缺少导入。 2025-12-04 09:21:35 +08:00
qk123
7407562ec5 维护系统->检查部位后端接口优化。 2025-12-03 17:15:35 +08:00
qk123
b3c27ec789 维护系统->检查方法前端页面优化、接口功能完善(搜索栏和导出表格未处理),后端接口优化。 2025-12-03 16:00:24 +08:00
qk123
601ae40666 维护系统->LIS分组前端页面开发,基础功能实现 2025-12-03 14:24:19 +08:00
3dda5ce72d 修改配置7 2025-12-03 13:48:25 +08:00
qk123
99d4c28b95 检查项目维护->Lis分组前端接口、后端实体优化。 2025-12-02 16:46:19 +08:00
qk123
0e70de6de7 Merge branch 'develop' of https://gitea.gentronhealth.com/Yajentine/his into develop 2025-12-02 16:44:57 +08:00
72eb1088df 修正前端PROD 2025-12-02 15:03:40 +08:00
a853c16854 修正prd 2025-12-02 14:43:35 +08:00
73a349f98a 冗余prod 2025-12-02 14:25:10 +08:00
5fb7a3f488 production 2025-12-02 14:12:06 +08:00
a8eb7d5697 prd->production 2025-12-02 14:08:09 +08:00
eb3b142ce4 修改配置 2025-12-02 14:03:49 +08:00
9f6a39ba30 修改配置文件 2025-12-02 14:02:25 +08:00
qk123
6fbdddf0ee 检查项目维护->Lis分组后端接口 2025-12-01 16:13:30 +08:00
45 changed files with 4493 additions and 736 deletions

View File

@@ -0,0 +1,39 @@
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
public class TestDeleteInspectionType {
public static void main(String[] args) {
try {
// 测试删除ID为1的检验类型
long inspectionTypeId = 1;
URL url = new URL("http://localhost:8080/system/inspection-type/" + inspectionTypeId);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("DELETE");
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("Accept", "application/json");
// 发送请求
int responseCode = connection.getResponseCode();
System.out.println("响应代码: " + responseCode);
// 读取响应
Scanner scanner;
if (responseCode >= 200 && responseCode < 300) {
scanner = new Scanner(connection.getInputStream());
} else {
scanner = new Scanner(connection.getErrorStream());
}
String response = scanner.useDelimiter("\\A").next();
System.out.println("响应内容: " + response);
scanner.close();
connection.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,27 @@
-- 向adm_organization表添加缺失字段的SQL脚本
-- 添加register_flag字段对应registerFlag属性
ALTER TABLE "adm_organization"
ADD COLUMN "register_flag" int4;
-- 添加location字段
ALTER TABLE "adm_organization"
ADD COLUMN "location" varchar(255);
-- 添加intro字段
ALTER TABLE "adm_organization"
ADD COLUMN "intro" varchar(1000);
-- 添加remark字段
ALTER TABLE "adm_organization"
ADD COLUMN "remark" varchar(1000);
-- 添加字段注释
COMMENT ON COLUMN "adm_organization"."register_flag" IS '挂号标志';
COMMENT ON COLUMN "adm_organization"."location" IS '科室位置';
COMMENT ON COLUMN "adm_organization"."intro" IS '科室简介';
COMMENT ON COLUMN "adm_organization"."remark" IS '备注';
-- 设置register_flag默认值为0不允许挂号
ALTER TABLE "adm_organization"
ALTER COLUMN "register_flag" SET DEFAULT 0;

View File

@@ -100,7 +100,18 @@ public class OrganizationAppServiceImpl implements IOrganizationAppService {
@Override @Override
public R<?> getOrgInfo(Long orgId) { public R<?> getOrgInfo(Long orgId) {
Organization organization = organizationService.getById(orgId); Organization organization = organizationService.getById(orgId);
return R.ok(organization, MessageUtils.createMessage(PromptMsgConstant.Common.M00004, new Object[] {"机构信息查询"})); if (organization == null) {
return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00006, new Object[] {"机构信息"}));
}
// 转换为DTO对象确保数据格式一致
OrganizationDto organizationDto = new OrganizationDto();
BeanUtils.copyProperties(organization, organizationDto);
organizationDto.setTypeEnum_dictText(EnumUtils.getInfoByValue(OrganizationType.class, organizationDto.getTypeEnum()));
organizationDto.setClassEnum_dictText(EnumUtils.getInfoByValue(OrganizationClass.class, organizationDto.getClassEnum()));
organizationDto.setActiveFlag_dictText(EnumUtils.getInfoByValue(AccountStatus.class, organizationDto.getActiveFlag()));
return R.ok(organizationDto, MessageUtils.createMessage(PromptMsgConstant.Common.M00004, new Object[] {"机构信息查询"}));
} }
/** /**

View File

@@ -60,4 +60,16 @@ public class OrganizationDto {
/** 子集合 */ /** 子集合 */
private List<OrganizationDto> children = new ArrayList<>(); private List<OrganizationDto> children = new ArrayList<>();
/** 挂号科室标记 */
private Integer registerFlag;
/** 科室位置 */
private String location;
/** 科室简介 */
private String intro;
/** 备注 */
private String remark;
} }

View File

@@ -2,7 +2,10 @@ package com.openhis.web.check.appservice;
import com.core.common.core.domain.R; import com.core.common.core.domain.R;
import com.openhis.web.check.dto.CheckMethodDto; import com.openhis.check.domain.CheckMethod;
import io.swagger.models.auth.In;
import javax.servlet.http.HttpServletResponse;
/** /**
* 检查方法Service接口 * 检查方法Service接口
@@ -14,11 +17,13 @@ public interface ICheckMethodAppService{
R<?> getCheckMethodList(); R<?> getCheckMethodList();
R<?> addCheckMethod(CheckMethodDto checkMethodDto); R<?> addCheckMethod(CheckMethod checkMethod);
R<?> updateCheckMethod(CheckMethodDto checkPartDto); R<?> updateCheckMethod(CheckMethod checkPart);
R<?> removeCheckMethod(Long code); R<?> removeCheckMethod(Integer checkMethodId);
R<?> searchCheckMethodList(Integer pageNo, Integer pageSize, String checkType, String name, String packageName);
R<?> exportCheckMethod(String checkType, String name, String packageName, HttpServletResponse response);
} }

View File

@@ -1,14 +1,20 @@
package com.openhis.web.check.appservice; package com.openhis.web.check.appservice;
import com.core.common.core.domain.R; import com.core.common.core.domain.R;
import com.openhis.web.check.dto.CheckPartDto; import com.openhis.check.domain.CheckPart;
import javax.servlet.http.HttpServletResponse;
public interface ICheckPartAppService { public interface ICheckPartAppService {
R<?> getCheckPartList(); R<?> getCheckPartList();
R<?> addCheckPart(CheckPartDto checkPartDto); R<?> addCheckPart(CheckPart checkPart);
R<?> removeCheckPart(Long code); R<?> removeCheckPart(Integer checkPartId);
R<?> updateCheckPart(CheckPartDto checkMethodDto); R<?> updateCheckPart(CheckPart checkPart);
R<?> searchCheckPartList(Integer pageNo, Integer pageSize, String checkType, String name, String packageName);
R<?> exportCheckPart(String checkType, String name, String packageName, HttpServletResponse response);
} }

View File

@@ -0,0 +1,14 @@
package com.openhis.web.check.appservice;
import com.core.common.core.domain.R;
import com.openhis.check.domain.LisGroupInfo;
public interface ILisGroupInfoAppService {
R<?> getLisGroupInfoList();
R<?> add(LisGroupInfo lisGroupInfo);
R<?> update(LisGroupInfo lisGroupInfo);
R<?> delete(Integer lisGroupInfoId);
}

View File

@@ -2,17 +2,20 @@ package com.openhis.web.check.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.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.core.common.core.domain.R; import com.core.common.core.domain.R;
import com.openhis.check.domain.CheckMethod; import com.openhis.check.domain.CheckMethod;
import com.openhis.check.service.ICheckMethodService; import com.openhis.check.service.ICheckMethodService;
import com.openhis.web.check.appservice.ICheckMethodAppService; import com.openhis.web.check.appservice.ICheckMethodAppService;
import com.openhis.web.check.dto.CheckMethodDto; import com.openhis.web.reportmanage.utils.ExcelFillerUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map;
@Service @Service
@Slf4j @Slf4j
@@ -28,65 +31,99 @@ public class CheckMethodAppServiceImpl implements ICheckMethodAppService {
} }
@Override @Override
public R<?> addCheckMethod(CheckMethodDto checkMethodDto) { public R<?> searchCheckMethodList(Integer pageNo, Integer pageSize, String checkType, String name, String packageName) {
//1.参数校验 LambdaQueryWrapper<CheckMethod> wrapper = new LambdaQueryWrapper<>();
if(ObjectUtil.isEmpty(checkMethodDto.getName())){ if (checkType != null && ObjectUtil.isNotEmpty(checkType)) {
return R.fail("检查方法名称不能为空"); wrapper.eq(CheckMethod::getCheckType, checkType);
} }
if(ObjectUtil.isEmpty(checkMethodDto.getCheckType())){ if (name != null && ObjectUtil.isNotEmpty(name)) {
return R.fail("检查类型不能为空"); wrapper.like(CheckMethod::getName, name);
} }
if(ObjectUtil.isEmpty(checkMethodDto.getCode())){ if (packageName != null && ObjectUtil.isNotEmpty(packageName)) {
return R.fail("代码不能为空"); wrapper.eq(CheckMethod::getPackageName, packageName);
} }
//2.判断是否有重复 List<CheckMethod> list = checkMethodService.list(wrapper);
LambdaQueryWrapper<CheckMethod> wrapper = new LambdaQueryWrapper<CheckMethod>() return R.ok(list);
.eq(CheckMethod::getName, checkMethodDto.getName())
.eq(CheckMethod::getCheckType, checkMethodDto.getCheckType())
.eq(CheckMethod::getCode, checkMethodDto.getCode());
if (checkMethodService.getOne(wrapper) != null){
return R.fail("检查方法已存在");
} }
//3.封装实体检查方法 @Override
CheckMethod checkMethod = new CheckMethod(); public R<?> addCheckMethod(CheckMethod checkMethod) {
checkMethod.setName(checkMethodDto.getName()); //1.数据校验
checkMethod.setCheckType(checkMethodDto.getCheckType()); if (ObjectUtil.isEmpty(checkMethod.getName())) {
checkMethod.setCode(checkMethodDto.getCode()); return R.fail("检查方法名称不能为空!");
checkMethod.setPackageName(checkMethodDto.getPackageName()); }
checkMethod.setExposureNum(checkMethodDto.getExposureNum()); if (ObjectUtil.isEmpty(checkMethod.getCode())) {
checkMethod.setOrderNum(checkMethodDto.getOrderNum()); return R.fail("检查方法代码不能为空!");
checkMethod.setRemark(checkMethodDto.getRemark()); }
//4.保存添加 if (ObjectUtil.isEmpty(checkMethod.getCheckType())) {
return R.fail("检查方法的检查类型不能为空!");
}
//2.保存
boolean save = checkMethodService.save(checkMethod); boolean save = checkMethodService.save(checkMethod);
return R.ok(); return R.ok(save);
} }
@Override @Override
public R<?> updateCheckMethod(CheckMethodDto checkMethodDto) { public R<?> updateCheckMethod(CheckMethod checkMethod) {
//1.数校验 //1.数校验
if(ObjectUtil.isEmpty(checkMethodDto.getName())){ if (ObjectUtil.isEmpty(checkMethod.getName())) {
return R.fail("检查方法名称不能为空"); return R.fail("检查方法名称不能为空");
} }
if(ObjectUtil.isEmpty(checkMethodDto.getCheckType())){ if (ObjectUtil.isEmpty(checkMethod.getCode())) {
return R.fail("检查类型不能为空"); return R.fail("检查方法代码不能为空");
} }
if(ObjectUtil.isEmpty(checkMethodDto.getCode())){ if (ObjectUtil.isEmpty(checkMethod.getCheckType())) {
return R.fail("代码不能为空"); return R.fail("检查方法的检查类型不能为空");
} }
//2. //2.更新
return R.ok(); boolean b = checkMethodService.updateById(checkMethod);
return R.ok(b);
} }
@Override @Override
public R<?> removeCheckMethod(Long code) { public R<?> removeCheckMethod(Integer checkMethodId) {
if (ObjectUtil.isEmpty(code)){ boolean remove = checkMethodService.removeById(checkMethodId);
return R.fail("检查方法代码不能为空");
}
LambdaQueryWrapper<CheckMethod> wrapper = new LambdaQueryWrapper<CheckMethod>().eq(CheckMethod::getCode, code);
boolean remove = checkMethodService.remove(wrapper);
return R.ok(remove); return R.ok(remove);
} }
@Override
public R<?> exportCheckMethod(String checkType, String name, String packageName, HttpServletResponse response) {
LambdaQueryWrapper<CheckMethod> wrapper = new LambdaQueryWrapper<>();
if (checkType != null && ObjectUtil.isNotEmpty(checkType)) {
wrapper.eq(CheckMethod::getCheckType, checkType);
}
if (name != null && ObjectUtil.isNotEmpty(name)) {
wrapper.like(CheckMethod::getName, name);
}
if (packageName != null && ObjectUtil.isNotEmpty(packageName)) {
wrapper.eq(CheckMethod::getPackageName, packageName);
}
List<CheckMethod> list = checkMethodService.list(wrapper);
if (list.isEmpty()) {
return R.fail("导出Excel失败,无数据。");
}
try {
// 准备表头key对应实体的字段名
Map<String, String> headers = new LinkedHashMap<>();
headers.put("checkType", "检查类型");
headers.put("code", "方法代码");
headers.put("name", "方法名称");
headers.put("packageName", "套餐名称");
headers.put("exposureNum", "曝光次数");
headers.put("orderNum", "序号");
headers.put("remark", "备注");
// 文件名,只传文字部分
String excelName = "检查方法列表";
// 导出到Excel
ExcelFillerUtil.makeExcelFile(response, list, headers, excelName, null);
} catch (IOException | IllegalAccessException e) {
e.printStackTrace();
return R.fail("导出Excel失败" + e.getMessage());
}
return R.ok(null, "导出Excel成功");
}
} }

View File

@@ -6,12 +6,16 @@ import com.core.common.core.domain.R;
import com.openhis.check.domain.CheckPart; import com.openhis.check.domain.CheckPart;
import com.openhis.check.service.ICheckPartService; import com.openhis.check.service.ICheckPartService;
import com.openhis.web.check.appservice.ICheckPartAppService; import com.openhis.web.check.appservice.ICheckPartAppService;
import com.openhis.web.check.dto.CheckPartDto; import com.openhis.web.reportmanage.utils.ExcelFillerUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map;
@Service @Service
@Slf4j @Slf4j
public class CheckPartAppServiceImpl implements ICheckPartAppService { public class CheckPartAppServiceImpl implements ICheckPartAppService {
@@ -24,54 +28,82 @@ public class CheckPartAppServiceImpl implements ICheckPartAppService {
} }
@Override @Override
public R<?> addCheckPart(CheckPartDto checkPartDto) { public R<?> searchCheckPartList(Integer pageNo, Integer pageSize, String checkType, String name, String packageName) {
//数据检验 LambdaQueryWrapper<CheckPart> wrapper = new LambdaQueryWrapper<>();
if(ObjectUtil.isEmpty(checkPartDto.getName())){ if (checkType != null && ObjectUtil.isNotEmpty(checkType)) {
return R.fail("检查项目名称不能为空"); wrapper.eq(CheckPart::getCheckType, checkType);
} }
if(ObjectUtil.isEmpty(checkPartDto.getCode())){ if (name != null && ObjectUtil.isNotEmpty(name)) {
return R.fail("检查项目代码不能为空"); wrapper.like(CheckPart::getName, name);
} }
if(ObjectUtil.isEmpty(checkPartDto.getCheckType())){ if (packageName != null && ObjectUtil.isNotEmpty(packageName)) {
return R.fail("检查项目类型不能为空"); wrapper.eq(CheckPart::getPackageName, packageName);
} }
//唯一性检验 List<CheckPart> list = checkPartService.list(wrapper);
LambdaQueryWrapper<CheckPart> wrapper = new LambdaQueryWrapper<CheckPart>() return R.ok(list);
.eq(CheckPart::getName, checkPartDto.getName())
.eq(CheckPart::getCode, checkPartDto.getCode())
.eq(CheckPart::getCheckType, checkPartDto.getCheckType());
if (checkPartService.getOne(wrapper) != null){
return R.fail("检查部位已存在");
}
//封装数据
CheckPart checkPart = new CheckPart();
checkPart.setName(checkPartDto.getName());
checkPart.setCode(checkPartDto.getCode());
checkPart.setCheckType(checkPartDto.getCheckType());
checkPart.setExposureNum(checkPartDto.getExposureNum());
checkPart.setPackageName(checkPartDto.getPackageName());
checkPart.setPrice(checkPartDto.getPrice());
checkPart.setNumber(checkPartDto.getNumber());
checkPart.setServiceScope(checkPartDto.getServiceScope());
checkPart.setSubType(checkPartDto.getSubType());
checkPart.setRemark(checkPartDto.getRemark());
//保存
checkPartService.save(checkPart);
return R.ok();
} }
@Override @Override
public R<?> removeCheckPart(Long code) { public R<?> addCheckPart(CheckPart checkPart) {
if (ObjectUtil.isEmpty(code)){ //数据检验
return R.fail("检查项目代码不能为空");
//保存
boolean save = checkPartService.save(checkPart);
return R.ok(save);
} }
LambdaQueryWrapper<CheckPart> wrapper = new LambdaQueryWrapper<CheckPart>().eq(CheckPart::getCode, code);
boolean remove = checkPartService.remove(wrapper); @Override
public R<?> removeCheckPart(Integer checkPartId) {
boolean remove = checkPartService.removeById(checkPartId);
return R.ok(remove); return R.ok(remove);
} }
@Override @Override
public R<?> updateCheckPart(CheckPartDto checkPartDto) { public R<?> updateCheckPart(CheckPart checkPart) {
return R.ok(); boolean b = checkPartService.updateById(checkPart);
return R.ok(b);
}
@Override
public R<?> exportCheckPart(String checkType, String name, String packageName, HttpServletResponse response) {
LambdaQueryWrapper<CheckPart> wrapper = new LambdaQueryWrapper<>();
if (checkType != null && ObjectUtil.isNotEmpty(checkType)) {
wrapper.eq(CheckPart::getCheckType, checkType);
}
if (name != null && ObjectUtil.isNotEmpty(name)) {
wrapper.like(CheckPart::getName, name);
}
if (packageName != null && ObjectUtil.isNotEmpty(packageName)) {
wrapper.eq(CheckPart::getPackageName, packageName);
}
List<CheckPart> list = checkPartService.list(wrapper);
if (list.isEmpty()) {
return R.fail("导出Excel失败,无数据。");
}
try {
// 准备表头key对应实体的字段名
Map<String, String> headers = new LinkedHashMap<>();
headers.put("checkType", "检查类型");
headers.put("code", "部位代码");
headers.put("name", "部位名称");
headers.put("packageName", "套餐名称");
headers.put("exposureNum", "曝光次数");
headers.put("price", "金额");
headers.put("number", "序号");
headers.put("serviceScope", "服务范围");
headers.put("subType", "下级医技类型");
headers.put("remark", "备注");
// 文件名,只传文字部分
String excelName = "检查部位列表";
// 导出到Excel
ExcelFillerUtil.makeExcelFile(response, list, headers, excelName, null);
} catch (IOException | IllegalAccessException e) {
e.printStackTrace();
return R.fail("导出Excel失败" + e.getMessage());
}
return R.ok(null, "导出Excel成功");
} }
} }

View File

@@ -0,0 +1,48 @@
package com.openhis.web.check.appservice.impl;
import cn.hutool.core.util.ObjectUtil;
import com.core.common.core.domain.R;
import com.openhis.check.domain.LisGroupInfo;
import com.openhis.check.service.ILisGroupInfoService;
import com.openhis.web.check.appservice.ILisGroupInfoAppService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
@Service
@Slf4j
public class LisGroupInfoAppServiceImpl implements ILisGroupInfoAppService {
@Resource
private ILisGroupInfoService lisGroupInfoService;
@Override
public R<?> getLisGroupInfoList() {
List<LisGroupInfo> list = lisGroupInfoService.list();
return R.ok(list);
}
@Override
public R<?> add(LisGroupInfo lisGroupInfo) {
if (ObjectUtil.isEmpty(lisGroupInfo)) {
return R.fail("信息不能为空");
}
boolean save = lisGroupInfoService.save(lisGroupInfo);
return R.ok(save);
}
@Override
public R<?> update(LisGroupInfo lisGroupInfo) {
if (ObjectUtil.isEmpty(lisGroupInfo)) {
return R.fail("信息不能为空");
}
boolean update = lisGroupInfoService.updateById(lisGroupInfo);
return R.ok( update);
}
@Override
public R<?> delete(Integer lisGroupInfoId) {
boolean b = lisGroupInfoService.removeById(lisGroupInfoId);
return R.ok(b);
}
}

View File

@@ -1,12 +1,13 @@
package com.openhis.web.check.controller; package com.openhis.web.check.controller;
import com.core.common.core.domain.R; import com.core.common.core.domain.R;
import com.openhis.check.domain.CheckMethod;
import com.openhis.web.check.appservice.ICheckMethodAppService; import com.openhis.web.check.appservice.ICheckMethodAppService;
import com.openhis.web.check.dto.CheckMethodDto;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
@RestController @RestController
@@ -18,29 +19,43 @@ public class CheckMethodController {
/* /*
* 获取检查方法 * 获取检查方法
* @Param检查方法 此处参数注释有问题,完全是按照需求给的图来注释的 * @Param 此处参数注释有问题,完全是按照需求给的图来注释的
*/ */
@GetMapping("/list") @GetMapping("/list")
public R<?> getCheckMethodList(){ public R<?> getCheckMethodList(){
return R.ok(checkMethodAppService.getCheckMethodList()); return R.ok(checkMethodAppService.getCheckMethodList());
} }
/*
* 条件查询检查方法
* @Para
* */
@GetMapping("/search")
public R<?> searchCheckMethodList(
@RequestParam(required = false) Integer pageNo,
@RequestParam(required = false) Integer pageSize,
@RequestParam(required = false) String checkType,
@RequestParam(required = false) String name,
@RequestParam(required = false) String packageName) {
return R.ok(checkMethodAppService.searchCheckMethodList(pageNo,pageSize,checkType,name,packageName));
}
/* /*
* 新增检查方法 * 新增检查方法
* @Param * @Param
*/ */
@PostMapping("/add") @PostMapping("/add")
public R<?> addCheckMethod(@RequestBody CheckMethodDto checkMethodDto){ public R<?> addCheckMethod(@RequestBody CheckMethod checkMethod){
return R.ok(checkMethodAppService.addCheckMethod(checkMethodDto)); return R.ok(checkMethodAppService.addCheckMethod(checkMethod));
} }
/* /*
* 删除检查方法 * 删除检查方法
* @Param code代码 * @Param code代码
*/ */
@DeleteMapping("/delete/{code}") @DeleteMapping("/delete/{checkMethodId}")
public R<?> deleteCheckMethod(@PathVariable Long code){ public R<?> deleteCheckMethod(@PathVariable Integer checkMethodId){
return R.ok(checkMethodAppService.removeCheckMethod(code)); return R.ok(checkMethodAppService.removeCheckMethod(checkMethodId));
} }
/* /*
@@ -48,7 +63,20 @@ public class CheckMethodController {
* @Param * @Param
*/ */
@PutMapping("/update") @PutMapping("/update")
public R<?> updateCheckMethod(@RequestBody CheckMethodDto checkMethodDto){ public R<?> updateCheckMethod(@RequestBody CheckMethod checkMethod){
return R.ok(checkMethodAppService.updateCheckMethod(checkMethodDto)); return R.ok(checkMethodAppService.updateCheckMethod(checkMethod));
}
/*
* 导出检查方法列表
* @Param
*/
@GetMapping("/export")
public void exportCheckMethod(
@RequestParam(required = false) String checkType,
@RequestParam(required = false) String name,
@RequestParam(required = false) String packageName,
HttpServletResponse response) {
checkMethodAppService.exportCheckMethod(checkType, name, packageName, response);
} }
} }

View File

@@ -1,12 +1,13 @@
package com.openhis.web.check.controller; package com.openhis.web.check.controller;
import com.core.common.core.domain.R; import com.core.common.core.domain.R;
import com.openhis.check.domain.CheckPart;
import com.openhis.web.check.appservice.ICheckPartAppService; import com.openhis.web.check.appservice.ICheckPartAppService;
import com.openhis.web.check.dto.CheckPartDto;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
@RestController @RestController
@Slf4j @Slf4j
@@ -24,22 +25,35 @@ public class CheckPartController {
return R.ok(checkPartAppService.getCheckPartList()); return R.ok(checkPartAppService.getCheckPartList());
} }
/*
* 条件搜索检查部位
* @Param
* */
@GetMapping("/search")
public R<?> searchCheckPartList(@RequestParam(required = false) Integer pageNo,
@RequestParam(required = false) Integer pageSize,
@RequestParam(required = false) String checkType,
@RequestParam(required = false) String name,
@RequestParam(required = false) String packageName){
return R.ok(checkPartAppService.searchCheckPartList(pageNo,pageSize,checkType,name,packageName));
}
/* /*
* 新增检查部位 * 新增检查部位
* @Param * @Param
*/ */
@PostMapping("/add") @PostMapping("/add")
public R<?> addCheckPart(@RequestBody CheckPartDto checkPartDto){ public R<?> addCheckPart(@RequestBody CheckPart checkPart){
return R.ok(checkPartAppService.addCheckPart(checkPartDto)); return R.ok(checkPartAppService.addCheckPart(checkPart));
} }
/* /*
* 删除检查部位 * 删除检查部位
* @Param code代码 * @Param code代码
*/ */
@DeleteMapping("/delete/{code}") @DeleteMapping("/delete/{checkPartId}")
public R<?> deleteCheckPart(@PathVariable Long code){ public R<?> deleteCheckPart(@PathVariable Integer checkPartId){
return R.ok(checkPartAppService.removeCheckPart(code)); return R.ok(checkPartAppService.removeCheckPart(checkPartId));
} }
/* /*
@@ -47,7 +61,20 @@ public class CheckPartController {
* @Param * @Param
*/ */
@PutMapping("/update") @PutMapping("/update")
public R<?> updateCheckPart(@RequestBody CheckPartDto checkPartDto){ public R<?> updateCheckPart(@RequestBody CheckPart checkPart){
return R.ok(checkPartAppService.updateCheckPart(checkPartDto)); return R.ok(checkPartAppService.updateCheckPart(checkPart));
}
/*
* 导出检查部位列表
* @Param
*/
@GetMapping("/export")
public void exportCheckPart(
@RequestParam(required = false) String checkType,
@RequestParam(required = false) String name,
@RequestParam(required = false) String packageName,
HttpServletResponse response) {
checkPartAppService.exportCheckPart(checkType, name, packageName, response);
} }
} }

View File

@@ -0,0 +1,56 @@
package com.openhis.web.check.controller;
import com.core.common.core.domain.R;
import com.openhis.web.check.appservice.ILisGroupInfoAppService;
import org.springframework.web.bind.annotation.*;
import com.openhis.check.domain.LisGroupInfo;
import javax.annotation.Resource;
@RestController
@RequestMapping("/check/lisGroupInfo")
public class LisGroupInfoController {
@Resource
private ILisGroupInfoAppService lisGroupInfoAppService;
/*
*
* 获取Lis分组信息
*
* */
@GetMapping("/list")
public R<?> getLisGroupInfoList(){
return R.ok(lisGroupInfoAppService.getLisGroupInfoList());
}
/*
*
* 新增Lis分组信息
*
* */
@PostMapping("/add")
public R<?> addLisGroupInfo(@RequestBody LisGroupInfo lisGroupInfo){
return R.ok(lisGroupInfoAppService.add(lisGroupInfo));
}
/*
*
* 修改Lis分组信息
*
* */
@PutMapping("/update")
public R<?> updateLisGroupInfo(@RequestBody LisGroupInfo lisGroupInfo){
return R.ok(lisGroupInfoAppService.update(lisGroupInfo));
}
/*
*
* 删除Lis分组信息
*
* */
@DeleteMapping("/{lisGroupInfoId}")
public R<?> deleteLisGroupInfo(@PathVariable Integer lisGroupInfoId){
return R.ok(lisGroupInfoAppService.delete(lisGroupInfoId));
}
}

View File

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

View File

@@ -0,0 +1,190 @@
package com.openhis.web.lab.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.core.common.core.controller.BaseController;
import com.core.common.core.domain.AjaxResult;
import com.openhis.lab.domain.InspectionType;
import com.openhis.lab.service.IInspectionTypeService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 检验类型管理Controller
*
* @author system
* @date 2025-12-09
*/
@RestController
@RequestMapping("/system/inspection-type")
@Slf4j
@AllArgsConstructor
public class InspectionTypeController extends BaseController {
// 辅助方法:将字节数组转换为十六进制字符串
private static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02X ", b));
}
return sb.toString().trim();
}
private final IInspectionTypeService inspectionTypeService;
private final TransactionTemplate transactionTemplate;
/**
* 获取检验类型列表
*/
@GetMapping("/list")
public AjaxResult list(InspectionType inspectionType) {
// 使用Wrapper构建查询条件确保order字段被正确处理
QueryWrapper<InspectionType> queryWrapper = new QueryWrapper<>(inspectionType);
List<InspectionType> list = inspectionTypeService.list(queryWrapper);
return AjaxResult.success(list);
}
/**
* 获取检验类型详细
*/
@GetMapping("/{inspectionTypeId}")
public AjaxResult getInfo(@PathVariable Long inspectionTypeId) {
return AjaxResult.success(inspectionTypeService.getById(inspectionTypeId));
}
/**
* 新增检验类型
*/
@PostMapping
public AjaxResult add(@RequestBody InspectionType inspectionType) {
// 确保新增时ID为null强制使用数据库自增序列
inspectionType.setId(null);
// 去除code字段的前后空格确保唯一性验证准确
if (inspectionType.getCode() != null) {
inspectionType.setCode(inspectionType.getCode().trim());
}
// 验证code字段是否唯一
QueryWrapper<InspectionType> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("code", inspectionType.getCode());
// 输出调试信息
System.out.println("检查编码唯一性code=" + inspectionType.getCode() + ", 长度=" + inspectionType.getCode().length());
System.out.println("code的十六进制表示" + bytesToHex(inspectionType.getCode().getBytes()));
// 直接查询具体记录,而不仅仅是计数
List<InspectionType> existingRecords = inspectionTypeService.list(queryWrapper);
System.out.println("数据库中存在的记录数:" + existingRecords.size());
for (InspectionType record : existingRecords) {
System.out.println("已存在记录id=" + record.getId() + ", code=" + record.getCode() + ", code长度=" + record.getCode().length() + ", code十六进制=" + bytesToHex(record.getCode().getBytes()));
}
if (!existingRecords.isEmpty()) {
return AjaxResult.error("检验类型编码已存在");
}
// 保存前再次验证
System.out.println("准备保存数据:" + inspectionType);
try {
// 使用事务确保一致性
return transactionTemplate.execute(status -> {
// 再次检查,防止并发问题
QueryWrapper<InspectionType> checkWrapper = new QueryWrapper<>();
checkWrapper.eq("code", inspectionType.getCode());
List<InspectionType> finalCheck = inspectionTypeService.list(checkWrapper);
if (!finalCheck.isEmpty()) {
return AjaxResult.error("检验类型编码已存在");
}
boolean result = inspectionTypeService.save(inspectionType);
System.out.println("保存结果:" + result);
return toAjax(result);
});
} catch (Exception e) {
System.out.println("保存失败,错误信息:" + e.getMessage());
// 捕获唯一性约束冲突异常
if (e.getMessage().contains("uk_inspection_type_code") ||
e.getMessage().contains("duplicate key value") ||
e.getMessage().contains("检验类型编码已存在")) {
return AjaxResult.error("检验类型编码已存在");
}
return AjaxResult.error("保存失败:" + e.getMessage());
}
}
/**
* 修改检验类型
*/
@PutMapping
public AjaxResult edit(@RequestBody InspectionType inspectionType) {
// 去除code字段的前后空格确保唯一性验证准确
if (inspectionType.getCode() != null) {
inspectionType.setCode(inspectionType.getCode().trim());
}
// 验证code字段是否唯一排除自身
QueryWrapper<InspectionType> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("code", inspectionType.getCode())
.ne("id", inspectionType.getId());
if (inspectionTypeService.count(queryWrapper) > 0) {
return AjaxResult.error("检验类型编码已存在");
}
try {
boolean result = inspectionTypeService.updateById(inspectionType);
return toAjax(result);
} catch (Exception e) {
// 捕获唯一性约束冲突异常
if (e.getMessage().contains("uk_inspection_type_code") ||
e.getMessage().contains("duplicate key value") ||
e.getMessage().contains("检验类型编码已存在")) {
return AjaxResult.error("检验类型编码已存在");
}
return AjaxResult.error("更新失败:" + e.getMessage());
}
}
/**
* 删除检验类型
*/
@DeleteMapping("/{inspectionTypeId}")
public AjaxResult remove(@PathVariable Long inspectionTypeId) {
log.info("删除检验类型ID: {}", inspectionTypeId);
try {
// 检查记录是否存在
InspectionType existing = inspectionTypeService.getById(inspectionTypeId);
log.info("删除前检查记录是否存在: {}", existing != null);
if (existing == null) {
log.warn("删除失败检验类型ID: {} 不存在", inspectionTypeId);
return AjaxResult.error("删除失败: 记录不存在");
}
// 使用MyBatis Plus的removeById方法执行逻辑删除
boolean result = inspectionTypeService.removeById(inspectionTypeId);
log.info("逻辑删除检验类型结果: {}", result);
AjaxResult response = toAjax(result);
log.info("删除响应: {}", response);
return response;
} catch (Exception e) {
log.error("删除检验类型失败ID: {}, 错误: {}", inspectionTypeId, e.getMessage(), e);
return AjaxResult.error("删除失败: " + e.getMessage());
}
}
// 测试删除接口,直接返回成功
@DeleteMapping("/test-delete/{id}")
public AjaxResult testDelete(@PathVariable Long id) {
log.info("测试删除接口ID: {}", id);
return AjaxResult.success("测试删除成功");
}
}

View File

@@ -80,6 +80,11 @@ mybatis-plus:
mapperLocations: classpath*:mapper/**/*Mapper.xml mapperLocations: classpath*:mapper/**/*Mapper.xml
# 加载全局的配置文件 # 加载全局的配置文件
configLocation: classpath:mybatis/mybatis-config.xml configLocation: classpath:mybatis/mybatis-config.xml
global-config:
db-config:
logic-delete-field: validFlag # 全局逻辑删除的实体字段名
logic-delete-value: 0 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 1 # 逻辑未删除值(默认为 0)
# PageHelper分页插件 # PageHelper分页插件
pagehelper: pagehelper:

View File

@@ -77,4 +77,16 @@ public class Organization extends HisBaseEntity {
/** 默认挂号医生 */ /** 默认挂号医生 */
private Long defDoctorId; private Long defDoctorId;
/** 挂号科室标记 */
private Integer registerFlag;
/** 科室位置 */
private String location;
/** 科室简介 */
private String intro;
/** 备注 */
private String remark;
} }

View File

@@ -3,7 +3,6 @@ package com.openhis.check.domain;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
@@ -26,7 +25,7 @@ public class CheckMethod {
* 检查方法ID * 检查方法ID
*/ */
@TableId(type = IdType.AUTO) @TableId(type = IdType.AUTO)
private Long id; private Integer id;
/* 检查类型 */ /* 检查类型 */
private String checkType; private String checkType;

View File

@@ -3,7 +3,6 @@ package com.openhis.check.domain;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
@@ -24,7 +23,7 @@ public class CheckPart {
/** 检查部位ID */ /** 检查部位ID */
@TableId(type = IdType.AUTO) @TableId(type = IdType.AUTO)
private Long id; private Integer id;
/** 检查部位名称 */ /** 检查部位名称 */
private String name; private String name;

View File

@@ -0,0 +1,40 @@
package com.openhis.check.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.experimental.Accessors;
import java.time.LocalDate;
import java.time.LocalDateTime;
@Data
@Accessors(chain = true)
@TableName(value = "lis_group_info",autoResultMap = true)
public class LisGroupInfo {
/** id */
@TableId(type = IdType.AUTO)
private Integer id;
/** 卫生机构 */
private String hospital;
/** 创建日期 */
private LocalDate date;
/** LIS分组名称 */
private String groupName;
/** 采血管类型 */
private String tube;
/** 备注 */
private String remark;
/** 创建时间 */
private LocalDateTime createTime;
/** 更新时间 */
private LocalDateTime updateTime;
}

View File

@@ -0,0 +1,9 @@
package com.openhis.check.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.openhis.check.domain.LisGroupInfo;
import org.springframework.stereotype.Repository;
@Repository
public interface LisGroupInfoMapper extends BaseMapper<LisGroupInfo> {
}

View File

@@ -0,0 +1,6 @@
package com.openhis.check.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.openhis.check.domain.LisGroupInfo;
public interface ILisGroupInfoService extends IService<LisGroupInfo>{
}

View File

@@ -0,0 +1,12 @@
package com.openhis.check.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.openhis.check.mapper.LisGroupInfoMapper;
import com.openhis.check.domain.LisGroupInfo;
import com.openhis.check.service.ILisGroupInfoService;
import org.springframework.stereotype.Service;
@Service
public class LisGroupInfoServiceImpl extends ServiceImpl<LisGroupInfoMapper,LisGroupInfo> implements ILisGroupInfoService{
}

View File

@@ -0,0 +1,72 @@
package com.openhis.lab.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.experimental.Accessors;
import java.time.LocalDateTime;
/**
* 检验类型
*
* @author system
* @date 2025-12-09
*/
@Data
@Accessors(chain = true)
@TableName(value = "inspection_type", autoResultMap = true)
public class InspectionType {
private static final long serialVersionUID = 1L;
/** 主键ID */
@TableId(type = IdType.AUTO)
private Long id;
/** 检验类型编码 */
private String code;
/** 检验类型名称 */
private String name;
/** 所属科室 */
private String department;
/** 排序 */
@TableField("\"order\"")
private Integer sortOrder;
/** 备注 */
private String remark;
/** 有效标志1有效0无效 */
@TableField("valid_flag")
@TableLogic(value = "1", delval = "0")
private Integer validFlag;
/** 创建时间 */
@TableField("created_at")
private LocalDateTime createdAt;
/** 更新时间 */
@TableField("updated_at")
private LocalDateTime updatedAt;
/** 版本号 */
private Integer version;
/**
* 以下字段数据库表中不存在用于禁用MyBatis Plus自动添加的字段
*/
@TableField(exist = false)
private String createBy;
@TableField(exist = false)
private String updateBy;
@TableField(exist = false)
private Integer tenantId;
}

View File

@@ -0,0 +1,16 @@
package com.openhis.lab.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.openhis.lab.domain.InspectionType;
import org.springframework.stereotype.Repository;
/**
* 检验类型Mapper接口
*
* @author system
* @date 2025-12-09
*/
@Repository
public interface InspectionTypeMapper extends BaseMapper<InspectionType> {
}

View File

@@ -0,0 +1,14 @@
package com.openhis.lab.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.openhis.lab.domain.InspectionType;
/**
* 检验类型Service接口
*
* @author system
* @date 2025-12-09
*/
public interface IInspectionTypeService extends IService<InspectionType> {
}

View File

@@ -0,0 +1,18 @@
package com.openhis.lab.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.openhis.lab.domain.InspectionType;
import com.openhis.lab.mapper.InspectionTypeMapper;
import com.openhis.lab.service.IInspectionTypeService;
import org.springframework.stereotype.Service;
/**
* 检验类型Service实现类
*
* @author system
* @date 2025-12-09
*/
@Service
public class InspectionTypeServiceImpl extends ServiceImpl<InspectionTypeMapper, InspectionType> implements IInspectionTypeService {
}

View File

@@ -4,4 +4,14 @@
"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.openhis.administration.mapper.OrganizationMapper"> <mapper namespace="com.openhis.administration.mapper.OrganizationMapper">
<!-- 自定义selectById方法确保包含所有字段包括新增字段 -->
<select id="selectById" parameterType="java.lang.Long" resultType="com.openhis.administration.domain.Organization">
SELECT id, bus_no, name, active_flag, type_enum, class_enum, py_str, wb_str,
yb_no, yb_name, caty, display_order, medins_id, medins_admdvs,
medins_type, medins_lv, def_doctor_id, create_by, create_time,
update_by, update_time, tenant_id, delete_flag,
register_flag, location, intro, remark
FROM adm_organization
WHERE id = #{id} AND delete_flag = '0'
</select>
</mapper> </mapper>

View File

@@ -2,13 +2,13 @@
VITE_APP_TITLE=医院信息管理系统 VITE_APP_TITLE=医院信息管理系统
# 生产环境配置 # 生产环境配置
VITE_APP_ENV=production VITE_APP_ENV= 'prod'
# OpenHIS管理系统/生产环境 # OpenHIS管理系统/生产环境
VITE_APP_BASE_API=/prd-api VITE_APP_BASE_API= '/prd-api'
# 租户ID配置 # 租户ID配置
VITE_APP_TENANT_ID=1 VITE_APP_TENANT_ID= '1'
# 是否在打包时开启压缩,支持 gzip 和 brotli # 是否在打包时开启压缩,支持 gzip 和 brotli
VITE_BUILD_COMPRESS = gzip VITE_BUILD_COMPRESS = gzip

View File

@@ -5,6 +5,7 @@ VITE_APP_TITLE = 医院信息管理系统
VITE_APP_ENV = 'test' VITE_APP_ENV = 'test'
# OpenHIS管理系统/测试环境 # OpenHIS管理系统/测试环境
VITE_APP_BASE_API = '/test-api' VITE_APP_BASE_API = '/test-api'
# 租户ID配置 # 租户ID配置

View File

@@ -6,8 +6,8 @@
"license": "MIT", "license": "MIT",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite --mode dev",
"build:prd": "vite build --mode prd", "build:prod": "vite build --mode prod",
"build:stage": "vite build --mode staging", "build:stage": "vite build --mode staging",
"build:test": "vite build --mode test", "build:test": "vite build --mode test",
"build:dev": "vite build --mode dev", "build:dev": "vite build --mode dev",

View File

@@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询检验类型列表
export function listInspectionType(query) {
return request({
url: '/system/inspection-type/list',
method: 'get',
params: query
})
}
// 查询检验类型详细
export function getInspectionType(inspectionTypeId) {
return request({
url: `/system/inspection-type/${inspectionTypeId}`,
method: 'get'
})
}
// 新增检验类型
export function addInspectionType(data) {
return request({
url: '/system/inspection-type',
method: 'post',
data: data
})
}
// 修改检验类型
export function updateInspectionType(data) {
return request({
url: '/system/inspection-type',
method: 'put',
data: data
})
}
// 删除检验类型
export function delInspectionType(inspectionTypeId) {
return request({
url: `/system/inspection-type/${inspectionTypeId}`,
method: 'delete'
})
}

View File

@@ -46,21 +46,112 @@ export function delCheckType(checkTypeId) {
// 查询检查方法列表 // 查询检查方法列表
export function listCheckMethod(query) { export function listCheckMethod(query) {
return request({ return request({
url: '/system/check-method/list', url: '/check/method/list',
method: 'get', method: 'get',
params: query params: query
}) })
} }
// 搜索检查方法列表
export function searchCheckMethod(query) {
return request({
url: '/check/method/search',
method: 'get',
params: query
})
}
// 新增检查方法
export function addCheckMethod(data) {
return request({
url: '/check/method/add',
method: 'post',
data: data
})
}
// 修改检查方法
export function updateCheckMethod(data) {
return request({
url: '/check/method/update',
method: 'put',
data: data
})
}
// 删除检查方法
export function delCheckMethod(checkMethodId) {
return request({
url: '/check/method/delete/' + checkMethodId,
method: 'delete'
})
}
// 导出检查方法
export function exportCheckMethod(query) {
return request({
url: '/check/method/export',
method: 'get',
params: query,
responseType: 'blob'
})
}
// 导出检查部位
export function exportCheckPart(query) {
return request({
url: '/check/part/export',
method: 'get',
params: query,
responseType: 'blob'
})
}
// 查询检查部位列表 // 查询检查部位列表
export function listCheckPart(query) { export function listCheckPart(query) {
return request({ return request({
url: '/system/check-part/list', url: '/check/part/list',
method: 'get', method: 'get',
params: query params: query
}) })
} }
// 搜索检查部位列表
export function searchCheckPart(query) {
return request({
url: '/check/part/search',
method: 'get',
params: query
})
}
// 新增检查部位
export function addCheckPart(data) {
return request({
url: '/check/part/add',
method: 'post',
data: data
})
}
// 删除检查部位
export function delCheckPart(checkPartId) {
return request({
url: '/check/part/delete/' + checkPartId,
method: 'delete'
})
}
// 更新检查部位
export function updateCheckPart(data) {
return request({
url: '/check/part/update',
method: 'put',
data: data
})
}
// 查询检查套餐列表 // 查询检查套餐列表
export function listCheckPackage(query) { export function listCheckPackage(query) {
return request({ return request({
@@ -103,3 +194,46 @@ export function delCheckPackage(id) {
method: 'delete' method: 'delete'
}) })
} }
// 查询LIS分组列表
export function listLisGroup(query) {
return request({
url: '/check/lisGroupInfo/list',
method: 'get',
params: query
})
}
// 根据ID查询LIS分组详情
export function getLisGroup(id) {
return request({
url: `/check/lisGroupInfo/${id}`,
method: 'get'
})
}
// 新增LIS分组
export function addLisGroup(data) {
return request({
url: '/check/lisGroupInfo/add',
method: 'post',
data: data
})
}
// 修改LIS分组
export function updateLisGroup(data) {
return request({
url: '/check/lisGroupInfo/update',
method: 'put',
data: data
})
}
// 删除LIS分组
export function delLisGroup(id) {
return request({
url: `/check/lisGroupInfo/${id}`,
method: 'delete'
})
}

View File

@@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询检验类型列表
export function listInspectionType(query) {
return request({
url: '/system/inspection-type/list',
method: 'get',
params: query
})
}
// 查询检验类型详细
export function getInspectionType(inspectionTypeId) {
return request({
url: '/system/inspection-type/' + inspectionTypeId,
method: 'get'
})
}
// 新增检验类型
export function addInspectionType(data) {
return request({
url: '/system/inspection-type',
method: 'post',
data: data
})
}
// 修改检验类型
export function updateInspectionType(data) {
return request({
url: '/system/inspection-type',
method: 'put',
data: data
})
}
// 删除检验类型
export function delInspectionType(inspectionTypeId) {
return request({
url: '/system/inspection-type/' + inspectionTypeId,
method: 'delete'
})
}

View File

@@ -47,11 +47,6 @@ export const constantRoutes = [
component: () => import('@/views/register'), component: () => import('@/views/register'),
hidden: true hidden: true
}, },
{
path: "/:pathMatch(.*)*",
component: () => import('@/views/error/404'),
hidden: true
},
{ {
path: '/401', path: '/401',
component: () => import('@/views/error/401'), component: () => import('@/views/error/401'),
@@ -83,6 +78,20 @@ export const constantRoutes = [
meta: { title: '个人中心', icon: 'user' } meta: { title: '个人中心', icon: 'user' }
} }
] ]
},
// 添加套餐管理相关路由到公共路由,确保始终可用
{
path: '/maintainSystem/Inspection/PackageManagement',
component: Layout,
hidden: true,
children: [
{
path: '',
component: () => import('@/views/maintainSystem/Inspection/PackageManagement.vue'),
name: 'DirectPackageManagement',
meta: { title: '套餐管理' }
}
]
} }
] ]
@@ -134,6 +143,20 @@ export const constantRoutes = [
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',
component: () => import('@/views/maintainSystem/Inspection/index.vue'),
name: 'Inspection',
meta: { title: '检验管理', icon: 'inspection' },
children: [
{
path: 'PackageManagement',
component: () => import('@/views/maintainSystem/Inspection/PackageManagement.vue'),
name: 'PackageManagement',
meta: { title: '套餐管理' }
}
]
} }
] ]
}, },
@@ -345,6 +368,13 @@ export const constantRoutes = [
// 合并常量路由和动态路由,确保所有路由都能被访问 // 合并常量路由和动态路由,确保所有路由都能被访问
const allRoutes = [...constantRoutes, ...dynamicRoutes]; const allRoutes = [...constantRoutes, ...dynamicRoutes];
// 添加404路由到所有路由的最后
allRoutes.push({
path: "/:pathMatch(.*)*",
component: () => import('@/views/error/404'),
hidden: true
});
const router = createRouter({ const router = createRouter({
history: createWebHistory(), history: createWebHistory(),
routes: allRoutes, routes: allRoutes,

View File

@@ -123,6 +123,9 @@ export function filterDynamicRoutes(routes) {
if (auth.hasRoleOr(route.roles)) { if (auth.hasRoleOr(route.roles)) {
res.push(route) res.push(route)
} }
} else {
// 如果没有权限设置,默认允许访问
res.push(route)
} }
}) })
return res return res

View File

@@ -33,8 +33,9 @@ export function deleteOrganization(orgIds) {
export function getOrgDetail(id) { export function getOrgDetail(id) {
return request({ return request({
url: '/base-data-manage/organization/organization?orgId=' + id, url: '/base-data-manage/organization/organization-getById',
method: 'get', method: 'get',
params: { orgId: id }
}) })
} }

View File

@@ -41,6 +41,14 @@
<el-table-column label="科室分类" align="center" prop="classEnum_dictText" /> <el-table-column label="科室分类" align="center" prop="classEnum_dictText" />
<el-table-column label="医保码" align="center" prop="ybNo" /> <el-table-column label="医保码" align="center" prop="ybNo" />
<el-table-column label="医保名称" align="center" prop="ybName" /> <el-table-column label="医保名称" align="center" prop="ybName" />
<el-table-column label="挂号科室" align="center">
<template #default="scope">
{{ scope.row.registerFlag ? '是' : '否' }}
</template>
</el-table-column>
<el-table-column label="科室位置" align="center" prop="location" show-overflow-tooltip />
<el-table-column label="科室简介" align="center" prop="intro" show-overflow-tooltip />
<el-table-column label="备注" align="center" prop="remark" show-overflow-tooltip />
<el-table-column label="状态" align="center" prop="activeFlag_dictText" /> <el-table-column label="状态" align="center" prop="activeFlag_dictText" />
<el-table-column label="操作" align="center"> <el-table-column label="操作" align="center">
<template #default="scope"> <template #default="scope">
@@ -129,6 +137,35 @@
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-form-item label="挂号科室" prop="registerFlag">
<el-radio-group v-model="form.registerFlag" size="large">
<el-radio :label="true"></el-radio>
<el-radio :label="false"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="科室位置" prop="location">
<el-input v-model="form.location" placeholder="请输入科室位置" maxlength="100" show-word-limit />
</el-form-item>
<el-form-item label="科室简介" prop="intro">
<el-input
v-model="form.intro"
type="textarea"
placeholder="请输入科室简介"
maxlength="500"
show-word-limit
:rows="4"
/>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input
v-model="form.remark"
type="textarea"
placeholder="请输入备注信息"
maxlength="1000"
show-word-limit
:rows="3"
/>
</el-form-item>
</el-form> </el-form>
<template #footer> <template #footer>
<div class="dialog-footer"> <div class="dialog-footer">
@@ -141,7 +178,7 @@
</template> </template>
<script setup name="Organization"> <script setup name="Organization">
import { getList, deleteOrganization, addOrganization, updateOrganization, disableOrg, initOrgTypeOption, enableOrg } from './components/api'; import { getList, deleteOrganization, addOrganization, updateOrganization, disableOrg, initOrgTypeOption, enableOrg, getOrgDetail } from './components/api';
const { proxy } = getCurrentInstance(); const { proxy } = getCurrentInstance();
const loading = ref(true); const loading = ref(true);
@@ -154,6 +191,10 @@ const form = ref({
name: undefined, name: undefined,
typeEnum: undefined, typeEnum: undefined,
busNoParent: undefined, busNoParent: undefined,
registerFlag: false, // 挂号科室标记
location: undefined, // 科室位置
intro: undefined, // 科室简介
remark: undefined, // 备注
}); });
const orgTableRef = ref(); const orgTableRef = ref();
const orgRef = ref(); const orgRef = ref();
@@ -169,6 +210,10 @@ const rules = ref({
{ min: 2, max: 20, message: '长度在 2 到 20 个字符', trigger: 'change' }, { min: 2, max: 20, message: '长度在 2 到 20 个字符', trigger: 'change' },
], ],
typeEnum: [{ required: true, message: '请选择科室类型', trigger: 'change' }], typeEnum: [{ required: true, message: '请选择科室类型', trigger: 'change' }],
// 新增字段验证规则
location: [{ required: false, message: '请输入科室位置', trigger: 'blur' }],
intro: [{ required: false, message: '请输入科室简介', trigger: 'blur' }],
remark: [{ required: false, message: '请输入备注信息', trigger: 'blur' }],
}); });
getPageList(); getPageList();
@@ -230,6 +275,10 @@ function initOption() {
function reset() { function reset() {
form.value.id = undefined; form.value.id = undefined;
form.value.registerFlag = false;
form.value.location = undefined;
form.value.intro = undefined;
form.value.remark = undefined;
orgRef.value.resetFields(); orgRef.value.resetFields();
} }
@@ -248,7 +297,7 @@ function getDictLabel(value) {
} }
function getPageList() { function getPageList() {
loading.value = false; loading.value = true;
getList(queryParams.value).then((res) => { getList(queryParams.value).then((res) => {
// 处理返回的科室数据,确保科室分类显示与系统标准字典一致 // 处理返回的科室数据,确保科室分类显示与系统标准字典一致
const processedData = res.data.records.map(item => { const processedData = res.data.records.map(item => {
@@ -269,6 +318,12 @@ function getPageList() {
organization.value = processedData; organization.value = processedData;
total.value = res.data.total; total.value = res.data.total;
}).catch(error => {
console.error('获取科室列表失败:', error);
proxy.$modal.msgError('获取科室列表失败,请稍后重试');
organization.value = [];
total.value = 0;
}).finally(() => {
loading.value = false; loading.value = false;
}); });
} }
@@ -285,17 +340,29 @@ function handelEdit(row) {
title.value = '编辑科室'; title.value = '编辑科室';
open.value = true; open.value = true;
setTimeout(() => {
form.value.id = row.id; // 调用后端API获取完整的科室信息确保包含所有字段
form.value.busNo = row.busNo; getOrgDetail(row.id).then(res => {
form.value.name = row.name; if (res.code === 200) {
form.value.ybNo = row.ybNo; const orgInfo = res.data;
form.value.ybName = row.ybName; form.value.id = orgInfo.id;
form.value.typeEnum = row.typeEnum; form.value.busNo = orgInfo.busNo;
form.value.name = orgInfo.name;
form.value.ybNo = orgInfo.ybNo;
form.value.ybName = orgInfo.ybName;
form.value.typeEnum = orgInfo.typeEnum;
// 确保科室分类值的类型正确,使其能正确匹配下拉选项中的值 // 确保科室分类值的类型正确,使其能正确匹配下拉选项中的值
form.value.classEnum = row.classEnum !== undefined ? String(row.classEnum) : undefined; form.value.classEnum = orgInfo.classEnum !== undefined ? String(orgInfo.classEnum) : undefined;
form.value.busNoParent = row.busNo.split('.').length > 1 ? row.busNo.split('.')[0] : undefined; form.value.busNoParent = orgInfo.busNo.split('.').length > 1 ? orgInfo.busNo.split('.')[0] : undefined;
}, 50); form.value.registerFlag = !!orgInfo.registerFlag;
form.value.location = orgInfo.location;
form.value.intro = orgInfo.intro;
form.value.remark = orgInfo.remark;
}
}).catch(error => {
console.error('获取科室信息失败:', error);
proxy.$modal.msgError('获取科室信息失败');
});
} }
function cancel() { function cancel() {
@@ -308,20 +375,43 @@ function cancel() {
function submitForm() { function submitForm() {
proxy.$refs['orgRef'].validate((valid) => { proxy.$refs['orgRef'].validate((valid) => {
if (valid) { if (valid) {
// 创建表单数据副本避免直接修改原始form对象
const formData = { ...form.value };
// 确保registerFlag从布尔值转换为整数true=1, false=0
formData.registerFlag = Number(formData.registerFlag ? 1 : 0);
// 确保classEnum字段有值数据库必填
// 如果未定义设置默认值1
if (formData.classEnum === undefined || formData.classEnum === null || formData.classEnum === '') {
formData.classEnum = 1;
}
// 确保classEnum为数字类型
formData.classEnum = Number(formData.classEnum);
// 验证提交数据
console.log('提交的数据:', formData);
if (form.value.id == undefined) { if (form.value.id == undefined) {
if (form.value.busNoParent) { if (form.value.busNoParent) {
form.value.busNo = form.value.busNoParent; formData.busNo = form.value.busNoParent;
} }
addOrganization(form.value).then((res) => { addOrganization(formData).then((res) => {
proxy.$modal.msgSuccess('操作成功'); proxy.$modal.msgSuccess('操作成功');
open.value = false; open.value = false;
getPageList(); getPageList();
}).catch(error => {
console.error('添加科室失败:', error);
proxy.$modal.msgError('添加科室失败,请稍后重试');
}); });
} else { } else {
updateOrganization(form.value).then((res) => { updateOrganization(formData).then((res) => {
proxy.$modal.msgSuccess('操作成功'); proxy.$modal.msgSuccess('操作成功');
open.value = false; open.value = false;
getPageList(); getPageList();
}).catch(error => {
console.error('更新科室失败:', error);
proxy.$modal.msgError('更新科室失败,请稍后重试');
}); });
} }
} }
@@ -340,8 +430,12 @@ function handleDelete() {
loading.value = true; loading.value = true;
deleteOrganization(selectRowIds.value.join(',')).then((res) => { deleteOrganization(selectRowIds.value.join(',')).then((res) => {
proxy.$modal.msgSuccess('操作成功'); proxy.$modal.msgSuccess('操作成功');
loading.value = false;
getPageList(); getPageList();
}).catch(error => {
console.error('删除科室失败:', error);
proxy.$modal.msgError('删除科室失败,请稍后重试');
}).finally(() => {
loading.value = false;
}); });
} }
// 停用 // 停用
@@ -349,6 +443,9 @@ function handleDisabled(id) {
disableOrg(id).then((res) => { disableOrg(id).then((res) => {
proxy.$modal.msgSuccess('操作成功'); proxy.$modal.msgSuccess('操作成功');
getPageList(); getPageList();
}).catch(error => {
console.error('停用科室失败:', error);
proxy.$modal.msgError('停用科室失败,请稍后重试');
}); });
} }
@@ -357,6 +454,9 @@ function handelEnable(id) {
enableOrg(id).then((res) => { enableOrg(id).then((res) => {
proxy.$modal.msgSuccess('操作成功'); proxy.$modal.msgSuccess('操作成功');
getPageList(); getPageList();
}).catch(error => {
console.error('启用科室失败:', error);
proxy.$modal.msgError('启用科室失败,请稍后重试');
}); });
} }

View File

@@ -0,0 +1,643 @@
<template>
<div class="package-management">
<!-- 左侧导航栏 -->
<nav class="sidebar" :class="{ active: sidebarActive }">
<div class="sidebar-item" @click="navigateToTab(0)">检验类型</div>
<div class="sidebar-item" @click="navigateToTab(1)">检验项目</div>
<div class="sidebar-item active" @click="navigateToTab(2)">套餐设置</div>
</nav>
<!-- 主内容区域 -->
<main class="content">
<!-- 导航切换按钮响应式 -->
<div class="menu-toggle" @click="toggleSidebar">
<i class="fas fa-bars"></i>
</div>
<!-- 查询过滤区域 -->
<section class="filter-bar">
<div class="filter-item">
<label>日期</label>
<input type="date" v-model="searchParams.startDate" placeholder="开始日期">
<span></span>
<input type="date" v-model="searchParams.endDate" placeholder="结束日期">
</div>
<div class="filter-item">
<label>卫生机构</label>
<select>
<option>演示医院</option>
</select>
</div>
<div class="filter-item">
<label>套餐名称</label>
<input type="text" v-model="searchParams.packageName" placeholder="套餐名称">
</div>
<div class="filter-item">
<label>套餐级别</label>
<select v-model="searchParams.packageLevel">
<option value="">请选择套餐级别</option>
<option value="全院套餐">全院套餐</option>
<option value="科室套餐">科室套餐</option>
<option value="个人套餐">个人套餐</option>
</select>
</div>
<div class="filter-item">
<label>套餐类别</label>
<select>
<option>检验套餐</option>
</select>
</div>
<div class="filter-item">
<label>科室</label>
<select>
<option value="">请选择科室</option>
<option value="内科">内科</option>
<option value="儿科">儿科</option>
<option value="外科">外科</option>
<option value="妇科">妇科</option>
</select>
</div>
<div class="filter-item">
<label>用户</label>
<select></select>
</div>
<!-- 操作按钮组 -->
<div class="button-group">
<button class="btn btn-search" @click="handleSearch"><i class="fas fa-search" style="margin-right: 6px;"></i>查询</button>
<button class="btn btn-reset" @click="handleReset"><i class="fas fa-redo" style="margin-right: 6px;"></i>重置</button>
<button class="btn btn-primary" @click="handleAdd"><i class="fas fa-plus" style="margin-right: 6px;"></i>新增</button>
<button class="btn btn-export" @click="handleExport"><i class="fas fa-download" style="margin-right: 6px;"></i>导出</button>
<button class="btn btn-copy" @click="returnToPackageSetup"><i class="fas fa-arrow-left" style="margin-right: 6px;"></i>返回</button>
</div>
</section>
<!-- 表格区域 -->
<section class="table-container">
<table>
<thead>
<tr>
<th>ID</th>
<th>卫生机构</th>
<th>日期</th>
<th>套餐名称</th>
<th>套餐类别</th>
<th>套餐级别</th>
<th>科室</th>
<th>用户</th>
<th class="text-right">金额</th>
<th class="text-right">服务费</th>
<th class="text-right">总金额</th>
<th>组合套餐</th>
<th>显示套餐名</th>
<th>启用标志</th>
<th>操作人</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="item in filteredData" :key="item.id">
<td>{{ item.id }}</td>
<td>{{ item.hospital }}</td>
<td>{{ item.date }}</td>
<td>{{ item.name }}</td>
<td>{{ item.type }}</td>
<td>{{ item.level }}</td>
<td>{{ item.dept || '-' }}</td>
<td>{{ item.user || '-' }}</td>
<td class="text-right">{{ item.amount.toFixed(2) }}</td>
<td class="text-right">{{ item.fee.toFixed(2) }}</td>
<td class="text-right">{{ item.total.toFixed(2) }}</td>
<td><span class="status-tag" :class="item.combined === '是' ? 'status-no' : 'status-yes'">{{ item.combined }}</span></td>
<td><span class="status-tag" :class="item.display === '是' ? 'status-yes' : 'status-no'">{{ item.display }}</span></td>
<td><span class="status-tag" :class="item.enabled === '是' ? 'status-yes' : 'status-no'">{{ item.enabled }}</span></td>
<td>{{ item.operator }}</td>
<td>
<div class="action-icons">
<el-button type="text" @click="handleEdit(item)"><el-icon><Edit /></el-icon></el-button>
<el-button type="text" @click="handleView(item)"><el-icon><View /></el-icon></el-button>
<el-button type="text" @click="handleDelete(item)"><el-icon><Delete /></el-icon></el-button>
</div>
</td>
</tr>
</tbody>
</table>
</section>
<!-- 分页组件 -->
<div class="pagination">
<button class="page-btn">&lt;</button>
<button class="page-btn active">1</button>
<button class="page-btn">2</button>
<button class="page-btn">3</button>
<button class="page-btn">...</button>
<button class="page-btn">10</button>
<button class="page-btn">&gt;</button>
<div class="total-count">总数{{ filteredData.length }}</div>
</div>
</main>
</div>
</template>
<script setup>
import { ref, computed } from 'vue';
import { useRouter } from 'vue-router';
import { Edit, View, Delete } from '@element-plus/icons-vue';
// 创建路由实例
const router = useRouter();
// 侧边栏状态
const sidebarActive = ref(false);
// 表格数据
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: 2341, hospital: '演示医院', date: '2025-10-31', name: '病理检测', type: '检验套餐', level: '全院套餐', dept: '', user: '', amount: 50.00, fee: 0.00, total: 50.00, combined: '否', display: '是', enabled: '是', operator: '徐斌'},
{id: 2340, hospital: '演示医院', date: '2025-10-31', name: '肝功能', type: '检验套餐', level: '全院套餐', dept: '', user: '', amount: 31.00, fee: 0.00, total: 31.00, combined: '否', display: '是', enabled: '是', operator: '徐斌'},
{id: 2339, hospital: '演示医院', date: '2025-10-31', name: '风湿', type: '检验套餐', level: '全院套餐', dept: '', user: '', amount: 119.00, fee: 0.00, total: 119.00, combined: '否', display: '是', enabled: '是', operator: '徐斌'},
{id: 2338, hospital: '演示医院', date: '2025-10-31', name: '尿常规', type: '检验套餐', level: '全院套餐', dept: '', user: '', amount: 1.00, fee: 0.00, total: 1.00, combined: '否', display: '是', enabled: '是', operator: '徐斌'},
{id: 2297, hospital: '演示医院', date: '2025-04-30', name: '测试', type: '检验套餐', level: '全院套餐', dept: '', user: '', amount: 241.00, fee: 0.00, total: 241.00, combined: '否', display: '是', enabled: '否', operator: '徐斌'},
]);
// 获取当前日期的函数格式为YYYY-MM-DD
function getCurrentDate() {
const today = new Date();
const year = today.getFullYear();
const month = String(today.getMonth() + 1).padStart(2, '0');
const day = String(today.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
}
// 搜索参数
const searchParams = ref({
startDate: getCurrentDate(),
endDate: getCurrentDate(),
packageName: '',
packageLevel: ''
});
// 过滤后的数据
const filteredData = computed(() => {
return tableData.value.filter(item => {
// 日期筛选
if (searchParams.value.startDate && item.date < searchParams.value.startDate) return false;
if (searchParams.value.endDate && item.date > searchParams.value.endDate) return false;
// 套餐名称筛选
if (searchParams.value.packageName && !item.name.toLowerCase().includes(searchParams.value.packageName.toLowerCase())) return false;
// 套餐级别筛选
if (searchParams.value.packageLevel && item.level !== searchParams.value.packageLevel) return false;
return true;
});
});
// 返回套餐设置主界面
function returnToPackageSetup() {
router.push('/maintainSystem/Inspection?tab=2');
}
// 导航到指定标签页
function navigateToTab(tabIndex) {
router.push(`/maintainSystem/Inspection?tab=${tabIndex}`);
}
// 切换侧边栏
function toggleSidebar() {
sidebarActive.value = !sidebarActive.value;
}
// 处理查询
function handleSearch() {
// 过滤逻辑已在computed属性中实现
}
// 处理重置
function handleReset() {
searchParams.value = {
startDate: getCurrentDate(),
endDate: getCurrentDate(),
packageName: '',
packageLevel: ''
};
}
// 处理新增
function handleAdd() {
router.push('/maintainSystem/Inspection?tab=2');
}
// 处理编辑
function handleEdit(item) {
alert(`准备编辑套餐:${item.name}\n数据已加载至编辑表单套餐设置主界面`);
}
// 处理查看
function handleView(item) {
alert(`准备查看套餐:${item.name}\n数据已加载至查看表单套餐设置主界面`);
}
// 处理删除
function handleDelete(item) {
if (confirm(`确定要删除套餐 "${item.name}" 吗?`)) {
const index = tableData.value.findIndex(i => i.id === item.id);
if (index !== -1) {
tableData.value.splice(index, 1);
alert(`套餐 "${item.name}" 已删除`);
}
}
}
// 处理导出
function handleExport() {
// 获取当前筛选后的数据
const dataToExport = filteredData.value;
// 转换为CSV格式
const csvContent = convertToCSV(dataToExport);
// 创建下载链接
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.setAttribute('href', url);
link.setAttribute('download', `套餐数据_${new Date().toISOString().slice(0,10)}.csv`);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
// 将数据转换为CSV格式的函数
function convertToCSV(data) {
if (data.length === 0) return '';
// 获取表头
const headers = Object.keys(data[0]);
// 构建CSV内容
let csv = headers.join(',') + '\n';
// 添加数据行
data.forEach(row => {
const values = headers.map(header => {
// 处理可能包含逗号的值
const value = row[header] === null || row[header] === undefined ? '' : row[header];
return `"${value.toString().replace(/"/g, '""')}"`;
});
csv += values.join(',') + '\n';
});
return csv;
}
</script>
<style>
:root {
--background: #FFFFFF;
--primary: #5C8DFF;
--primary-hover: #7DA3FF;
--text-primary: #333333;
--text-secondary: #666666;
--text-disabled: #CCCCCC;
--danger: #FF6B6B;
--border: #E0E0E0;
--header-bg: #F5F5F5;
--row-hover: #FAFAFA;
--table-border: #E8E8E8;
--sidebar-width: 200px;
--content-padding: 24px;
--secondary: #8E8E93;
--secondary-hover: #A7A7AB;
--success: #4CAF50;
--info: #2196F3;
--btn-search: #6c757d;
--btn-reset: #17a2b8;
--btn-add: #28a745;
--btn-export: #17a2b8;
--btn-copy: #6c757d;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'PingFang SC', 'Microsoft YaHei', sans-serif;
}
/* 移除body样式避免影响其他页面 */
.package-management {
display: flex;
height: 100vh;
background-color: var(--background);
color: var(--text-primary);
overflow: hidden;
}
/* 左侧导航栏 */
.sidebar {
width: var(--sidebar-width);
background-color: var(--background);
border-right: 1px solid var(--border);
height: 100%;
display: flex;
flex-direction: column;
}
.sidebar-item {
padding: 16px 24px;
font-size: 14px;
color: var(--text-primary);
cursor: pointer;
transition: all 0.2s;
display: flex;
align-items: center;
}
.sidebar-item:hover {
background-color: #f0f8ff;
}
.sidebar-item.active {
background-color: var(--primary);
color: white;
}
/* 主内容区域 */
.content {
flex: 1;
display: flex;
flex-direction: column;
height: 100%;
overflow: hidden;
}
/* 查询过滤栏 */
.filter-bar {
padding: 16px var(--content-padding);
border-bottom: 1px solid var(--border);
display: flex;
flex-wrap: wrap;
gap: 12px;
align-items: center;
}
.filter-item {
display: flex;
align-items: center;
gap: 8px;
}
.filter-item label {
font-size: 14px;
color: var(--text-secondary);
white-space: nowrap;
}
input, select {
height: 32px;
border-radius: 4px;
border: 1px solid var(--border);
padding: 0 8px;
font-size: 14px;
min-width: 120px;
}
input:focus, select:focus {
outline: none;
border-color: var(--primary);
}
/* 按钮样式 */
.btn {
padding: 6px 16px;
border-radius: 6px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
height: 36px;
display: inline-flex;
align-items: center;
justify-content: center;
transition: all 0.2s ease;
border: none;
box-shadow: 0 1px 2px rgba(0,0,0,0.05);
min-width: 80px;
}
.btn-primary {
background-color: var(--primary);
color: white;
border: 1px solid var(--primary);
box-shadow: 0 2px 4px rgba(92, 141, 255, 0.2);
}
.btn-text {
background-color: #F5F7FA;
color: var(--secondary);
border: 1px solid var(--border);
}
.btn-search {
background-color: var(--btn-search);
color: white;
}
.btn-reset {
background-color: var(--btn-reset);
color: white;
}
.btn-export {
background-color: var(--btn-export);
color: white;
}
.btn-copy {
background-color: var(--btn-copy);
color: white;
}
.btn-text:hover {
background-color: #EBEEF2;
color: var(--text-primary);
border-color: var(--secondary-hover);
}
.btn-danger {
background-color: var(--danger);
color: white;
}
.btn:hover {
opacity: 0.9;
}
.btn-primary:hover {
background-color: var(--primary-hover);
border-color: var(--primary-hover);
}
.button-group {
display: flex;
gap: 12px;
margin-left: auto;
flex-wrap: wrap;
}
/* 表格区域 */
.table-container {
flex: 1;
overflow: auto;
padding: 0 var(--content-padding) var(--content-padding);
}
table {
width: 100%;
border-collapse: collapse;
font-size: 14px;
}
th, td {
padding: 8px;
text-align: left;
border-bottom: 1px solid var(--table-border);
}
th {
background-color: var(--header-bg);
font-weight: 500;
position: sticky;
top: 0;
}
tr:hover {
background-color: var(--row-hover);
}
.text-right {
text-align: right;
}
/* 状态标签 */
.status-tag {
padding: 0 8px;
border-radius: 2px;
font-size: 12px;
height: 20px;
display: inline-flex;
align-items: center;
justify-content: center;
}
.status-yes {
background-color: #f6ffed;
border: 1px solid #b7eb8f;
color: #389e0d;
}
.status-no {
background-color: #fff2f0;
border: 1px solid #ffccc7;
color: var(--danger);
}
/* 操作图标 */
.action-icons {
display: flex;
gap: 8px;
}
.action-icons .el-button {
color: var(--danger);
padding: 0;
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
}
.action-icons .el-button:hover {
background-color: #fff2f0;
color: var(--danger);
}
/* 分页样式 */
.pagination {
display: flex;
justify-content: center;
align-items: center;
padding: 16px 0;
gap: 8px;
}
.page-btn {
width: 32px;
height: 32px;
border-radius: 4px;
border: 1px solid var(--border);
background-color: white;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
}
.page-btn.active {
background-color: var(--primary);
color: white;
border: none;
}
.total-count {
margin-left: 16px;
font-size: 14px;
color: var(--text-secondary);
}
/* 响应式设计 */
@media (max-width: 1200px) {
.sidebar {
transform: translateX(calc(-1 * var(--sidebar-width)));
position: absolute;
z-index: 100;
transition: transform 0.3s;
}
.sidebar.active {
transform: translateX(0);
}
.menu-toggle {
display: flex;
align-items: center;
justify-content: center;
height: 40px;
width: 40px;
position: absolute;
top: 16px;
left: 16px;
z-index: 101;
cursor: pointer;
background: white;
border: 1px solid var(--border);
border-radius: 4px;
}
.filter-bar {
padding-top: 64px;
}
}
</style>
<style scoped>
/* 移除未使用的图标样式 */
</style>
<style scoped>
/* 移除自动生成的未使用样式 */
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -135,6 +135,7 @@
import { ref, reactive } from 'vue'; import { ref, reactive } 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';
const router = useRouter(); const router = useRouter();
const formRef = ref(null); const formRef = ref(null);
@@ -198,46 +199,72 @@ const handleSave = async () => {
await formRef.value.validate(); await formRef.value.validate();
} }
// 将表单数据转换为系统配置格式 // 将表单数据转换为系统配置格式,并添加必要的默认值
const configData = [ const configData = [
{ configKey: 'medicalRecordFee', configValue: formData.medicalRecordFee, configName: '病历本费用' }, { configKey: 'medicalRecordFee', configValue: formData.medicalRecordFee, configName: '病历本费用', configType: 'Y' },
{ configKey: 'patientCardFee', configValue: formData.patientCardFee, configName: '就诊卡费' }, { configKey: 'patientCardFee', configValue: formData.patientCardFee, configName: '就诊卡费', configType: 'Y' },
{ configKey: 'medicalRecordFlag', configValue: formData.medicalRecordFlag ? '1' : '0', configName: '病历费入账标志' }, { configKey: 'medicalRecordFlag', configValue: formData.medicalRecordFlag ? '1' : '0', configName: '病历费入账标志', configType: 'Y' },
{ configKey: 'isNightShift', configValue: formData.isNightShift ? '1' : '0', configName: '是否启用晚班' }, { configKey: 'isNightShift', configValue: formData.isNightShift ? '1' : '0', configName: '是否启用晚班', configType: 'Y' },
{ configKey: 'patientCardFlag', configValue: formData.patientCardFlag ? '1' : '0', configName: '就诊卡记账标志' }, { configKey: 'patientCardFlag', configValue: formData.patientCardFlag ? '1' : '0', configName: '就诊卡记账标志', configType: 'Y' },
{ configKey: 'morningStartTime', configValue: formData.morningStartTime, configName: '上午接诊起始时间' }, { configKey: 'morningStartTime', configValue: formData.morningStartTime, configName: '上午接诊起始时间', configType: 'Y' },
{ configKey: 'autoGenerateOutpatientNo', configValue: formData.autoGenerateOutpatientNo ? '1' : '0', configName: '自动产生门诊号' }, { configKey: 'autoGenerateOutpatientNo', configValue: formData.autoGenerateOutpatientNo ? '1' : '0', configName: '自动产生门诊号', configType: 'Y' },
{ configKey: 'allowModifyOutpatientNo', configValue: formData.allowModifyOutpatientNo ? '1' : '0', configName: '建档时是否允许修改门诊号' }, { configKey: 'allowModifyOutpatientNo', configValue: formData.allowModifyOutpatientNo ? '1' : '0', configName: '建档时是否允许修改门诊号', configType: 'Y' },
{ configKey: 'afternoonStartTime', configValue: formData.afternoonStartTime, configName: '下午起始时间' }, { configKey: 'afternoonStartTime', configValue: formData.afternoonStartTime, configName: '下午起始时间', configType: 'Y' },
{ configKey: 'eveningStartTime', configValue: formData.eveningStartTime, configName: '晚上起始时间' }, { configKey: 'eveningStartTime', configValue: formData.eveningStartTime, configName: '晚上起始时间', configType: 'Y' },
{ configKey: 'registrationValidity', configValue: formData.registrationValidity, configName: '挂号有效期' }, { configKey: 'registrationValidity', configValue: formData.registrationValidity, configName: '挂号有效期', configType: 'Y' },
{ configKey: 'registrationDocumentMode', configValue: formData.registrationDocumentMode, configName: '挂号单据模式' }, { configKey: 'registrationDocumentMode', configValue: formData.registrationDocumentMode, configName: '挂号单据模式', configType: 'Y' },
{ configKey: 'exemptFlag', configValue: formData.exemptFlag ? '1' : '0', configName: '减免标志' }, { configKey: 'exemptFlag', configValue: formData.exemptFlag ? '1' : '0', configName: '减免标志', configType: 'Y' },
{ configKey: 'consultationFlag', configValue: formData.consultationFlag ? '1' : '0', configName: '义诊标志' }, { configKey: 'consultationFlag', configValue: formData.consultationFlag ? '1' : '0', configName: '义诊标志', configType: 'Y' },
{ configKey: 'enableHolidayFeeFloat', configValue: formData.enableHolidayFeeFloat ? '1' : '0', configName: '启用法定节假日挂号费浮动' }, { configKey: 'enableHolidayFeeFloat', configValue: formData.enableHolidayFeeFloat ? '1' : '0', configName: '启用法定节假日挂号费浮动', configType: 'Y' },
{ configKey: 'guardianAge', configValue: formData.guardianAge, configName: '监护人规定年龄' }, { configKey: 'guardianAge', configValue: formData.guardianAge, configName: '监护人规定年龄', configType: 'Y' },
{ configKey: 'enableDoubleScreen', configValue: formData.enableDoubleScreen ? '1' : '0', configName: '门诊挂号启用双屏' }, { configKey: 'enableDoubleScreen', configValue: formData.enableDoubleScreen ? '1' : '0', configName: '门诊挂号启用双屏', configType: 'Y' },
{ configKey: 'optionalRegistrationType', configValue: formData.optionalRegistrationType ? '1' : '0', configName: '挂号类型可选择' }, { configKey: 'optionalRegistrationType', configValue: formData.optionalRegistrationType ? '1' : '0', configName: '挂号类型可选择', configType: 'Y' },
{ configKey: 'isPrint', configValue: formData.isPrint ? '1' : '0', configName: '是否打印挂号单' }, { configKey: 'isPrint', configValue: formData.isPrint ? '1' : '0', configName: '是否打印挂号单', configType: 'Y' },
]; ];
let successCount = 0;
let failedParams = [];
// 调用系统配置API保存每个参数 // 调用系统配置API保存每个参数
for (const config of configData) { for (const config of configData) {
try {
// 先查询是否存在该配置 // 先查询是否存在该配置
const existingConfig = await getConfigKey(config.configKey); const existingConfig = await getConfigKey(config.configKey, { skipErrorMsg: true });
if (existingConfig.data) {
// 如果存在则更新 if (existingConfig.data && existingConfig.data.configId) {
await updateConfig({ ...config, configId: existingConfig.data.configId }); // 如果存在则更新保留原有数据的configId
await updateConfig({
...config,
configId: existingConfig.data.configId,
createTime: existingConfig.data.createTime, // 保留创建时间
remark: existingConfig.data.remark || '收费系统配置参数' // 保留或设置默认备注
});
} else { } else {
// 如果不存在则新增 // 如果不存在则新增,添加默认备注
await addConfig(config); await addConfig({
...config,
remark: '收费系统配置参数'
});
}
successCount++;
} catch (paramError) {
console.error(`保存参数 ${config.configName} (${config.configKey}) 失败:`, paramError);
failedParams.push(config.configName);
// 继续处理下一个参数,不中断整体流程
} }
} }
ElMessage.success('保存成功'); // 根据保存结果显示相应消息
if (failedParams.length === 0) {
ElMessage.success(`所有 ${successCount} 个参数保存成功`);
} else if (successCount > 0) {
ElMessage.warning(`${successCount} 个参数保存成功,但以下 ${failedParams.length} 个参数保存失败: ${failedParams.join(', ')}`);
} else {
ElMessage.error(`所有参数保存失败,请检查系统配置`);
}
} catch (error) { } catch (error) {
console.error('保存失败:', error); console.error('保存过程中发生错误:', error);
ElMessage.error('保存失败,请重试'); ElMessage.error('保存操作异常,请重试');
} }
}; };

View File

@@ -83,7 +83,7 @@
v-for="(item, index) in tableData" v-for="(item, index) in tableData"
:key="index" :key="index"
:class="{ 'editing-row': item.editing, 'child-row': item.row.includes('.') }" :class="{ 'editing-row': item.editing, 'child-row': item.row.includes('.') }"
@click="handleRowClick(item)" @click="handleEdit(index)"
> >
<td>{{ item.row }}</td> <td>{{ item.row }}</td>
<td> <td>
@@ -198,15 +198,12 @@
<template v-else-if="activeMenu === '检查方法'"> <template v-else-if="activeMenu === '检查方法'">
<div class="header"> <div class="header">
<h1>{{ activeMenu }}管理</h1> <h1>{{ activeMenu }}管理</h1>
<div class="header-actions">
<button class="btn btn-add-new" @click="handleAddNewRow">+
</button>
</div> </div>
</div> <div class="search-bar search-bar-method">
<div class="search-bar"> <div class="search-filters">
<div class="search-item"> <div class="search-item">
<label>检查类型</label> <label>检查类型</label>
<el-select v-model="searchParams.checkMethod" placeholder="选择检查类型" style="width: 150px"> <el-select v-model="searchParamsMethod.checkType" placeholder="选择检查类型" style="width: 150px">
<el-option <el-option
v-for="type in checkTypes" v-for="type in checkTypes"
:key="type" :key="type"
@@ -218,20 +215,21 @@
</div> </div>
<div class="search-item"> <div class="search-item">
<label>名称</label> <label>名称</label>
<el-input placeholder="名称/编码" v-model="searchParams.name" /> <el-input placeholder="名称/编码" v-model="searchParamsMethod.name" />
</div> </div>
<div class="search-item"> <div class="search-item">
<label>费用套餐</label> <label>费用套餐</label>
<el-select v-model="searchParams.packageId" placeholder="选择使用套餐" style="width: 150px"> <el-select v-model="searchParamsMethod.packageName" placeholder="选择使用套餐" style="width: 150px">
<el-option <el-option
v-for="pkg in checkPackages" v-for="pkg in checkPackages"
:key="pkg.id" :key="pkg.id"
:label="pkg.name" :label="pkg.name"
:value="pkg.id" :value="pkg.name"
> >
</el-option> </el-option>
</el-select> </el-select>
</div> </div>
</div>
<div class="search-actions"> <div class="search-actions">
<el-button type="primary" :style="{ backgroundColor: hoverAddButton ? '#8a49e0' : '#722ED1', borderColor: hoverAddButton ? '#8a49e0' : '#722ED1' }" @mouseenter="hoverAddButton = true" @mouseleave="hoverAddButton = false" @click="handleAddNewRow">新增</el-button> <el-button type="primary" :style="{ backgroundColor: hoverAddButton ? '#8a49e0' : '#722ED1', borderColor: hoverAddButton ? '#8a49e0' : '#722ED1' }" @mouseenter="hoverAddButton = true" @mouseleave="hoverAddButton = false" @click="handleAddNewRow">新增</el-button>
<el-button type="primary" @click="handleSearch">查询</el-button> <el-button type="primary" @click="handleSearch">查询</el-button>
@@ -257,10 +255,10 @@
</thead> </thead>
<tbody> <tbody>
<tr <tr
v-for="(item, index) in tableData" v-for="(item, index) in checkMethodData"
:key="index" :key="index"
:class="{ 'editing-row': item.editing }" :class="{ 'editing-row': item.editing }"
@click="handleRowClick(item)" @click=""
> >
<td>{{ item.row }}</td> <td>{{ item.row }}</td>
<td> <td>
@@ -321,6 +319,9 @@
</template> </template>
</td> </td>
<td class="actions"> <td class="actions">
<button class="btn btn-edit" @click.stop="handleEdit(index)">
</button>
<button class="btn btn-confirm" @click.stop="handleConfirm(index)"> <button class="btn btn-confirm" @click.stop="handleConfirm(index)">
</button> </button>
@@ -338,15 +339,11 @@
<template v-else-if="activeMenu === '检查部位'"> <template v-else-if="activeMenu === '检查部位'">
<div class="header"> <div class="header">
<h1>{{ activeMenu }}管理</h1> <h1>{{ activeMenu }}管理</h1>
<div class="header-actions">
<button class="btn btn-add-new" @click="handleAddNewRow">+
</button>
</div> </div>
</div> <div class="search-bar search-bar-part">
<div class="search-bar">
<div class="search-item"> <div class="search-item">
<label>检查类型</label> <label>检查类型</label>
<el-select v-model="searchParams.checkType" placeholder="选择检查类型" style="width: 150px"> <el-select v-model="searchParamsPart.checkType" placeholder="选择检查类型" style="width: 150px">
<el-option <el-option
v-for="type in checkTypes" v-for="type in checkTypes"
:key="type" :key="type"
@@ -358,11 +355,11 @@
</div> </div>
<div class="search-item"> <div class="search-item">
<label>名称</label> <label>名称</label>
<el-input placeholder="名称/编码" v-model="searchParams.name" /> <el-input placeholder="名称/编码" v-model="searchParamsPart.name" />
</div> </div>
<div class="search-item"> <div class="search-item">
<label>费用套餐</label> <label>费用套餐</label>
<el-input placeholder="费用套餐" v-model="searchParams.packageName" /> <el-input placeholder="费用套餐" v-model="searchParamsPart.packageName" />
</div> </div>
<div class="search-actions"> <div class="search-actions">
@@ -379,12 +376,12 @@
<tr> <tr>
<th style="width: 50px;"></th> <th style="width: 50px;"></th>
<th style="width: 100px;">*编码</th> <th style="width: 100px;">*编码</th>
<th style="width: 150px;">*名称</th> <th style="width: 100px;">*名称</th>
<th style="width: 120px;">检查类型</th> <th style="width: 120px;">检查类型</th>
<th style="width: 100px;">曝光次数</th> <th style="width: 80px;">曝光次数</th>
<th style="width: 120px;">费用套餐</th> <th style="width: 120px;">费用套餐</th>
<th style="width: 100px;">金额</th> <th style="width: 80px;">金额</th>
<th style="width: 80px;">序号</th> <th style="width: 50px;">序号</th>
<th style="width: 120px;">服务范围</th> <th style="width: 120px;">服务范围</th>
<th style="width: 120px;">下级医技类型</th> <th style="width: 120px;">下级医技类型</th>
<th style="width: 150px;">备注</th> <th style="width: 150px;">备注</th>
@@ -393,10 +390,10 @@
</thead> </thead>
<tbody> <tbody>
<tr <tr
v-for="(item, index) in tableData" v-for="(item, index) in checkPartData"
:key="index" :key="index"
:class="{ 'editing-row': item.editing }" :class="{ 'editing-row': item.editing }"
@click="handleRowClick(item)" @click=""
> >
<td>{{ item.row }}</td> <td>{{ item.row }}</td>
<td> <td>
@@ -480,6 +477,9 @@
</template> </template>
</td> </td>
<td class="actions"> <td class="actions">
<button class="btn btn-edit" @click.stop="handleEdit(index)">
</button>
<button class="btn btn-confirm" @click.stop="handleConfirm(index)"> <button class="btn btn-confirm" @click.stop="handleConfirm(index)">
</button> </button>
@@ -503,10 +503,10 @@
</template> </template>
<script setup> <script setup>
import { ref, reactive, onMounted } from 'vue'; import { ref, reactive, onMounted, computed } from 'vue';
import { ElMessage } from 'element-plus'; import { ElMessage, ElMessageBox } from 'element-plus';
import { getDicts } from '@/api/system/dict/data'; import { getDicts } from '@/api/system/dict/data';
import { listCheckType, listCheckMethod, listCheckPart, listCheckPackage, addCheckType, updateCheckType, delCheckType } from '@/api/system/checkType'; import { listCheckType, listCheckMethod, listCheckPart, listCheckPackage, searchCheckMethod, searchCheckPart, addCheckType, updateCheckType, delCheckType, addCheckMethod, updateCheckMethod, delCheckMethod, addCheckPart, updateCheckPart, delCheckPart, exportCheckMethod, exportCheckPart } from '@/api/system/checkType';
import PackageSettings from './components/PackageSettings.vue'; import PackageSettings from './components/PackageSettings.vue';
import PackageManagement from './components/PackageManagement.vue'; import PackageManagement from './components/PackageManagement.vue';
@@ -528,19 +528,55 @@ const checkParts = ref([]);
const checkPackages = ref([]); const checkPackages = ref([]);
const departments = ref([]); const departments = ref([]);
// 表格数据 // 表格数据 - 为每个菜单创建独立的数据存储
const tableData = reactive([]); const checkTypeData = reactive([]);
const checkMethodData = reactive([]);
const checkPartData = reactive([]);
const packageData = reactive([]);
// 搜索条件 // 当前显示的表格数据
const searchParams = reactive({ const tableData = computed(() => {
checkMethod: '', switch(activeMenu.value) {
name: '', case '检查类型':
packageId: '', return checkTypeData;
packageName: '', case '检查方法':
return checkMethodData;
case '检查部位':
return checkPartData;
case '套餐设置':
return packageData;
default:
return [];
}
});
// 搜索条件 - 为每个菜单创建独立的搜索参数
const searchParamsType = reactive({});
const searchParamsMethod = reactive({
checkType: '', checkType: '',
checkPartCode: '', name: '',
checkPartName: '', packageName: ''
visible: '' });
const searchParamsPart = reactive({
checkType: '',
name: '',
packageName: ''
});
// 获取当前菜单对应的搜索参数
const currentSearchParams = computed(() => {
switch(activeMenu.value) {
case '检查类型':
return searchParamsType;
case '检查方法':
return searchParamsMethod;
case '检查部位':
return searchParamsPart;
case '套餐设置':
return searchParamsMethod; // 套餐设置可能共享检查方法的搜索参数
default:
return {};
}
}); });
// 按钮悬停状态 // 按钮悬停状态
@@ -564,10 +600,10 @@ onMounted(async () => {
// 获取所有不重复的检查类型值 // 获取所有不重复的检查类型值
checkTypes.value = [...new Set(types.map(item => item.type))]; checkTypes.value = [...new Set(types.map(item => item.type))];
// 构建表格数据 // 构建检查类型表格数据
tableData.splice(0, tableData.length); checkTypeData.splice(0, checkTypeData.length);
types.forEach((item, index) => { types.forEach((item, index) => {
tableData.push({ checkTypeData.push({
id: item.id, // 保存id字段用于判断是新增还是修改 id: item.id, // 保存id字段用于判断是新增还是修改
row: (index + 1).toString(), row: (index + 1).toString(),
code: item.code, code: item.code,
@@ -585,19 +621,28 @@ onMounted(async () => {
// 获取检查方法数据 // 获取检查方法数据
const methodResponse = await listCheckMethod(); const methodResponse = await listCheckMethod();
if (methodResponse && methodResponse.data) { if (methodResponse && methodResponse.data) {
checkMethods.value = methodResponse.data; // 确保data是数组类型
checkMethods.value = Array.isArray(methodResponse.data) ? methodResponse.data : [];
} else {
checkMethods.value = [];
} }
// 获取检查部位数据 // 获取检查部位数据
const partResponse = await listCheckPart(); const partResponse = await listCheckPart();
if (partResponse && partResponse.data) { if (partResponse && partResponse.data) {
checkParts.value = partResponse.data; // 确保data是数组类型
checkParts.value = Array.isArray(partResponse.data) ? partResponse.data : [];
} else {
checkParts.value = [];
} }
// 获取检查套餐数据 // 获取检查套餐数据
const packageResponse = await listCheckPackage(); const packageResponse = await listCheckPackage();
if (packageResponse && packageResponse.data) { if (packageResponse && packageResponse.data) {
checkPackages.value = packageResponse.data; // 确保data是数组类型
checkPackages.value = Array.isArray(packageResponse.data) ? packageResponse.data : [];
} else {
checkPackages.value = [];
} }
} catch (error) { } catch (error) {
@@ -660,18 +705,22 @@ function handleSaveSuccess() {
// 根据菜单加载对应数据 // 根据菜单加载对应数据
async function loadMenuData(menu) { async function loadMenuData(menu) {
try { try {
tableData.splice(0, tableData.length);
switch(menu) { switch(menu) {
case '检查类型': case '检查类型':
// 清空检查类型数据
checkTypeData.splice(0, checkTypeData.length);
const typeResponse = await listCheckType(); const typeResponse = await listCheckType();
if (typeResponse && typeResponse.data) { if (typeResponse && typeResponse.data) {
// 获取所有不重复的检查类型 // 确保data是数组类型
checkTypes.value = [...new Set(typeResponse.data.map(item => item.type))]; const typeData = Array.isArray(typeResponse.data) ? typeResponse.data : [];
typeResponse.data.forEach((item, index) => { // 获取所有不重复的检查类型值
checkTypes.value = [...new Set(typeData.map(item => item.type))];
typeData.forEach((item, index) => {
// 直接使用数据库中的department值不进行转换 // 直接使用数据库中的department值不进行转换
tableData.push({ checkTypeData.push({
id: item.id, // 保存id字段用于判断是新增还是修改 id: item.id, // 保存id字段用于判断是新增还是修改
row: (index + 1).toString(), row: (index + 1).toString(),
code: item.code, code: item.code,
@@ -688,10 +737,38 @@ async function loadMenuData(menu) {
break; break;
case '检查方法': case '检查方法':
const methodResponse = await listCheckMethod(); // 清空检查方法数据
if (methodResponse && methodResponse.data) { checkMethodData.splice(0, checkMethodData.length);
methodResponse.data.forEach((item, index) => {
tableData.push({ // 构建检查方法的搜索参数
const methodParams = {
pageNo: 1,
pageSize: 100, // 默认获取100条数据可以根据需要调整
checkType: searchParamsMethod.checkType,
name: searchParamsMethod.name,
packageName: searchParamsMethod.packageName
};
try {
const methodResponse = await searchCheckMethod(methodParams);
// 确保data是数组适配不同的后端返回格式
let methodData = [];
if (methodResponse) {
if (Array.isArray(methodResponse)) {
methodData = methodResponse;
} else if (methodResponse.data && Array.isArray(methodResponse.data)) {
methodData = methodResponse.data;
} else if (methodResponse.data && methodResponse.data.data && Array.isArray(methodResponse.data.data)) {
methodData = methodResponse.data.data;
} else if (methodResponse.data && methodResponse.data.records) {
methodData = methodResponse.data.records;
}
}
// 处理数组数据
if (methodData.length > 0) {
methodData.forEach((item, index) => {
checkMethodData.push({
id: item.id, // 保存id字段用于判断是新增还是修改 id: item.id, // 保存id字段用于判断是新增还是修改
row: (index + 1).toString(), row: (index + 1).toString(),
code: item.code, code: item.code,
@@ -704,22 +781,47 @@ async function loadMenuData(menu) {
actions: true actions: true
}); });
}); });
} else {
ElMessage.warning('未获取到检查方法数据');
}
} catch (error) {
ElMessage.error(`加载检查方法数据失败: ${error.message || '未知错误'}`);
} }
break; break;
case '检查部位': case '检查部位':
// 清空检查部位数据
checkPartData.splice(0, checkPartData.length);
// 构建检查部位的搜索参数 // 构建检查部位的搜索参数
const partSearchParams = { const partParams = {
code: searchParams.checkPartCode, pageNo: 1,
name: searchParams.name, pageSize: 100, // 默认获取100条数据可以根据需要调整
checkType: searchParams.checkType, checkType: searchParamsPart.checkType,
packageName: searchParams.packageName, name: searchParamsPart.name,
visible: searchParams.visible packageName: searchParamsPart.packageName
}; };
const partResponse = await listCheckPart(partSearchParams); try {
if (partResponse && partResponse.data) { const partResponse = await searchCheckPart(partParams);
partResponse.data.forEach((item, index) => {
tableData.push({ // 确保data是数组适配不同的后端返回格式
let partData = [];
if (partResponse) {
if (Array.isArray(partResponse)) {
partData = partResponse;
} else if (partResponse.data && Array.isArray(partResponse.data)) {
partData = partResponse.data;
} else if (partResponse.data && partResponse.data.data && Array.isArray(partResponse.data.data)) {
partData = partResponse.data.data;
} else if (partResponse.data && partResponse.data.records) {
partData = partResponse.data.records;
}
}
// 处理数组数据
if (partData.length > 0) {
partData.forEach((item, index) => {
checkPartData.push({
id: item.id, // 保存id字段用于判断是新增还是修改 id: item.id, // 保存id字段用于判断是新增还是修改
row: (index + 1).toString(), row: (index + 1).toString(),
code: item.code, code: item.code,
@@ -735,6 +837,11 @@ async function loadMenuData(menu) {
actions: true actions: true
}); });
}); });
} else {
ElMessage.warning('未获取到检查部位数据');
}
} catch (error) {
ElMessage.error(`加载检查部位数据失败: ${error.message || '未知错误'}`);
} }
break; break;
@@ -750,54 +857,159 @@ async function loadMenuData(menu) {
} }
} }
// 处理行点击,进入编辑状态 // 处理编辑按钮点击
function handleRowClick(item) { function handleEdit(index) {
if (!item.editing) { const item = tableData[index];
item.editing = true; item.editing = true;
} }
}
// 处理确认按钮点击 // 处理确认按钮点击
async function handleConfirm(index) { async function handleConfirm(index) {
const item = tableData[index]; const item = tableData[index];
try { try {
// 根据是否有id判断是新增还是修改 // 根据当前激活的菜单调用不同的API
if (activeMenu.value === '检查方法') {
// 检查方法的保存逻辑
if (item.id) { if (item.id) {
// 修改操作 // 修改操作:只传递必要字段
await updateCheckType(item); const updateData = {
id: item.id,
code: item.code,
name: item.name,
checkType: item.checkType,
packageName: item.packageName,
exposureNum: item.exposureNum,
orderNum: item.orderNum,
remark: item.remark
};
await updateCheckMethod(updateData);
} else { } else {
// 新增操作 // 新增操作:只传递必要字段
const newItem = await addCheckType(item); const addData = {
code: item.code,
name: item.name,
checkType: item.checkType,
packageName: item.packageName,
exposureNum: item.exposureNum,
orderNum: item.orderNum,
remark: item.remark
};
console.log('准备新增检查方法:', addData);
const newItem = await addCheckMethod(addData);
console.log('新增检查方法返回结果:', newItem);
// 将新增的id赋值给本地数据 // 将新增的id赋值给本地数据
item.id = newItem.id; item.id = newItem.id;
} }
} else if (activeMenu.value === '检查部位') {
// 检查部位的保存逻辑
if (item.id) {
// 修改操作:只传递必要字段
const updateData = {
id: item.id,
code: item.code,
name: item.name,
checkType: item.checkType,
exposureNum: item.exposureNum,
packageName: item.packageName,
price: item.price,
number: item.number,
serviceScope: item.serviceScope,
subType: item.subType,
remark: item.remark
};
await updateCheckPart(updateData);
} else {
// 新增操作:只传递必要字段
const addData = {
code: item.code,
name: item.name,
checkType: item.checkType,
exposureNum: item.exposureNum,
packageName: item.packageName,
price: item.price,
number: item.number,
serviceScope: item.serviceScope,
subType: item.subType,
remark: item.remark
};
console.log('准备新增检查部位:', addData);
const newItem = await addCheckPart(addData);
console.log('新增检查部位返回结果:', newItem);
// 将新增的id赋值给本地数据
item.id = newItem.id;
}
} else {
// 检查类型的保存逻辑
if (item.id) {
// 修改操作:只传递必要字段
const updateData = {
id: item.id,
code: item.code,
name: item.name,
type: item.type,
selected: item.selected,
department: item.department,
number: item.number,
remark: item.remark
};
await updateCheckType(updateData);
} else {
// 新增操作:只传递必要字段
const addData = {
code: item.code,
name: item.name,
type: item.type,
selected: item.selected,
department: item.department,
number: item.number,
remark: item.remark
};
console.log('准备新增检查类型:', addData);
const newItem = await addCheckType(addData);
console.log('新增检查类型返回结果:', newItem);
// 将新增的id赋值给本地数据
item.id = newItem.id;
}
}
// 退出编辑状态 // 退出编辑状态
tableData[index].editing = false; tableData[index].editing = false;
// 显示保存成功提示 // 显示保存成功提示
alert(`${item.row} 行数据已保存`); ElMessage.success(`${item.row} 行数据已保存`);
} catch (error) { } catch (error) {
console.error('保存失败:', error); console.error('保存失败,错误信息:', error);
alert('保存失败,请稍后重试'); console.error('保存失败,错误详情:', error.response ? error.response.data : error);
ElMessage.error('保存失败,请稍后重试');
} }
} }
// 处理删除按钮点击 // 处理删除按钮点击
async function handleDelete(index) { async function handleDelete(index) {
if (confirm('确定要删除这一行吗?')) { ElMessageBox.confirm('确定要删除这一行吗?', '系统提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async () => {
const item = tableData[index]; const item = tableData[index];
try { try {
// 如果有id调用API删除数据库中的数据 // 如果有id调用API删除数据库中的数据
if (item.id) { if (item.id) {
if (activeMenu.value === '检查方法') {
await delCheckMethod(item.id);
} else if (activeMenu.value === '检查部位') {
await delCheckPart(item.id);
} else {
await delCheckType(item.id); await delCheckType(item.id);
} }
}
// 从数组中删除该行数据 // 从数组中删除该行数据
tableData.splice(index, 1); tableData.splice(index, 1);
alert('删除成功!'); ElMessage.success('删除成功!');
} catch (error) { } catch (error) {
console.error('删除失败:', error); ElMessage.error('删除失败,请稍后重试');
alert('删除失败,请稍后重试');
}
} }
}).catch(() => {
// 用户取消删除操作
});
} }
// 处理添加新行按钮点击 // 处理添加新行按钮点击
@@ -834,10 +1046,10 @@ function handleAddNewRow() {
row: String(maxRowNum + 1), row: String(maxRowNum + 1),
code: '', code: '',
name: '', name: '',
type: '', checkType: '',
department: '', packageName: '',
amount: '0.00', exposureNum: 0,
number: '999999', orderNum: 0,
remark: '', remark: '',
editing: true, // 新行默认进入编辑状态 editing: true, // 新行默认进入编辑状态
isNew: true, // 标记为新增行 isNew: true, // 标记为新增行
@@ -903,29 +1115,153 @@ function handleAdd(index) {
} }
// 处理搜索功能 // 处理搜索功能
function handleSearch() { async function handleSearch() {
console.log('搜索条件:', searchParams); try {
// 这里可以根据activeMenu和searchParams实现不同的搜索逻辑 console.log('搜索条件:', currentSearchParams.value);
ElMessage.info(`正在搜索${activeMenu.value}数据...`); // ElMessage.info(`正在搜索${activeMenu.value}数据...`);
// 模拟搜索延迟 switch(activeMenu.value) {
setTimeout(() => { case '检查方法':
// 根据activeMenu执行相应的搜索逻辑 // 清空检查方法数据
loadMenuData(activeMenu.value); checkMethodData.splice(0, checkMethodData.length);
}, 300);
// 构建检查方法的搜索参数
const methodParams = {
pageNo: 1,
pageSize: 100, // 默认获取100条数据可以根据需要调整
checkType: searchParamsMethod.checkType,
name: searchParamsMethod.name,
packageName: searchParamsMethod.packageName
};
const methodResponse = await searchCheckMethod(methodParams);
// 确保data是数组适配不同的后端返回格式
let methodData = [];
if (methodResponse) {
if (Array.isArray(methodResponse)) {
methodData = methodResponse;
} else if (methodResponse.data && Array.isArray(methodResponse.data)) {
methodData = methodResponse.data;
} else if (methodResponse.data && methodResponse.data.data && Array.isArray(methodResponse.data.data)) {
methodData = methodResponse.data.data;
} else if (methodResponse.data && methodResponse.data.records) {
methodData = methodResponse.data.records;
}
}
// 处理数组数据
if (methodData.length > 0) {
methodData.forEach((item, index) => {
checkMethodData.push({
id: item.id, // 保存id字段用于判断是新增还是修改
row: (index + 1).toString(),
code: item.code,
name: item.name,
checkType: item.checkType || '',
packageName: item.packageName || '',
exposureNum: item.exposureNum || 0,
orderNum: item.orderNum || 0,
remark: item.remark || '',
actions: true
});
});
ElMessage.success(`搜索到${methodData.length}条检查方法数据`);
} else {
ElMessage.warning('未搜索到检查方法数据');
}
break;
case '检查部位':
// 清空检查部位数据
checkPartData.splice(0, checkPartData.length);
// 构建检查部位的搜索参数
const partParams = {
pageNo: 1,
pageSize: 100, // 默认获取100条数据可以根据需要调整
checkType: searchParamsPart.checkType,
name: searchParamsPart.name,
packageName: searchParamsPart.packageName
};
const partResponse = await searchCheckPart(partParams);
// 确保data是数组适配不同的后端返回格式
let partData = [];
if (partResponse) {
if (Array.isArray(partResponse)) {
partData = partResponse;
} else if (partResponse.data && Array.isArray(partResponse.data)) {
partData = partResponse.data;
} else if (partResponse.data && partResponse.data.data && Array.isArray(partResponse.data.data)) {
partData = partResponse.data.data;
} else if (partResponse.data && partResponse.data.records) {
partData = partResponse.data.records;
}
}
// 处理数组数据
if (partData.length > 0) {
partData.forEach((item, index) => {
checkPartData.push({
id: item.id, // 保存id字段用于判断是新增还是修改
row: (index + 1).toString(),
code: item.code,
name: item.name,
checkType: item.checkType || '',
exposureNum: item.exposureNum || 0,
packageName: item.packageName || '',
price: item.price || 0,
number: item.number || '999999',
serviceScope: item.serviceScope || '',
subType: item.subType || '',
remark: item.remark || '',
actions: true
});
});
ElMessage.success(`搜索到${partData.length}条检查部位数据`);
} else {
ElMessage.warning('未搜索到检查部位数据');
}
break;
default:
// 其他菜单使用原有的加载逻辑
await loadMenuData(activeMenu.value);
break;
}
} catch (error) {
console.error('搜索失败:', error);
ElMessage.error(`搜索${activeMenu.value}数据失败: ${error.message || '未知错误'}`);
}
} }
// 处理重置功能 // 处理重置功能
function handleReset() { function handleReset() {
// 重置所有搜索条件 // 根据当前活动菜单重置对应的搜索条件
searchParams.checkMethod = ''; switch(activeMenu.value) {
searchParams.name = ''; case '检查类型':
searchParams.packageId = ''; for (const key in searchParamsType) {
searchParams.packageName = ''; searchParamsType[key] = '';
searchParams.checkType = ''; }
searchParams.checkPartCode = ''; break;
searchParams.checkPartName = '';
searchParams.visible = ''; case '检查方法':
searchParamsMethod.checkType = '';
searchParamsMethod.name = '';
searchParamsMethod.packageName = '';
break;
case '检查部位':
searchParamsPart.checkType = '';
searchParamsPart.name = '';
searchParamsPart.packageName = '';
break;
default:
break;
}
ElMessage.info('搜索条件已重置'); ElMessage.info('搜索条件已重置');
} }
@@ -933,10 +1269,51 @@ function handleReset() {
// 处理导出表格功能 // 处理导出表格功能
function handleExport() { function handleExport() {
console.log('导出表格:', activeMenu.value); console.log('导出表格:', activeMenu.value);
ElMessage.success(`正在导出${activeMenu.value}数据,请稍候...`);
// 这里可以实现实际的导出逻辑 if (activeMenu.value === '检查方法') {
// 例如调用API或使用前端库生成Excel文件 // 调用检查方法导出API
exportCheckMethod(searchParamsMethod).then(blobData => {
// 直接使用blobData创建下载链接因为response拦截器已经返回了res.data
const blob = new Blob([blobData], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
// 设置文件名
link.setAttribute('download', `检查方法数据_${new Date().toISOString().slice(0, 10)}.xlsx`);
document.body.appendChild(link);
link.click();
// 清理
document.body.removeChild(link);
window.URL.revokeObjectURL(url);
ElMessage.success('检查方法数据导出成功');
}).catch(error => {
console.error('导出检查方法数据失败:', error);
ElMessage.error('导出检查方法数据失败');
});
} else if (activeMenu.value === '检查部位') {
// 调用检查部位导出API
exportCheckPart(searchParamsPart).then(blobData => {
// 直接使用blobData创建下载链接因为response拦截器已经返回了res.data
const blob = new Blob([blobData], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
// 设置文件名
link.setAttribute('download', `检查部位数据_${new Date().toISOString().slice(0, 10)}.xlsx`);
document.body.appendChild(link);
link.click();
// 清理
document.body.removeChild(link);
window.URL.revokeObjectURL(url);
ElMessage.success('检查部位数据导出成功');
}).catch(error => {
console.error('导出检查部位数据失败:', error);
ElMessage.error('导出检查部位数据失败');
});
} else {
// 其他菜单的导出逻辑可以在这里扩展
ElMessage.warning('该功能尚未实现');
}
} }
</script> </script>
@@ -1039,6 +1416,26 @@ select {
gap: 16px; gap: 16px;
} }
/* 检查方法搜索栏特定样式 */
.search-bar-method {
display: flex;
flex-direction: column;
gap: 16px;
}
.search-bar-method .search-filters {
display: flex;
align-items: center;
gap: 16px;
width: 100%;
}
.search-bar-method .search-actions {
margin-left: auto;
display: flex;
gap: 8px;
}
.search-item { .search-item {
display: flex; display: flex;
align-items: center; align-items: center;
@@ -1148,7 +1545,7 @@ th {
font-size: 14px; font-size: 14px;
font-weight: 500; font-weight: 500;
line-height: 24px; line-height: 24px;
text-align: left; text-align: center;
border-bottom: 1px solid #D9D9D9; border-bottom: 1px solid #D9D9D9;
} }
@@ -1159,13 +1556,16 @@ td {
font-weight: 400; font-weight: 400;
line-height: 24px; line-height: 24px;
border-bottom: 1px solid #e8e8e8; border-bottom: 1px solid #e8e8e8;
text-align: center;
} }
/* 操作按钮样式 */ /* 操作按钮样式 */
.actions { .actions {
display: flex; display: flex;
justify-content: flex-end; justify-content: center;
gap: 8px; gap: 8px;
position: relative;
z-index: 10;
} }
.btn { .btn {
@@ -1180,6 +1580,18 @@ td {
transition: all 0.2s ease; transition: all 0.2s ease;
font-size: 16px; font-size: 16px;
font-weight: bold; font-weight: bold;
position: relative;
z-index: 10;
background-color: #66b1ff;
color: white;
}
.btn-delete {
background-color: #FF4D4F;
color: white;
font-size: 14px;
z-index: 20;
pointer-events: auto;
} }
.btn-confirm { .btn-confirm {
@@ -1187,6 +1599,12 @@ td {
color: white; color: white;
} }
.btn-edit {
background-color: #FFC107;
color: white;
font-size: 14px;
}
.btn-add { .btn-add {
background-color: #1890FF; background-color: #1890FF;
color: white; color: white;

View File

@@ -0,0 +1,999 @@
<template>
<div class="lis-group-maintain">
<!-- 标题区域 -->
<div class="header">
<h2>LIS分组维护</h2>
</div>
<!-- 表格展示区域 -->
<div class="table-container">
<table class="data-table">
<thead>
<tr>
<th style="width: 50px;"></th>
<th style="width: 150px;">卫生机构</th>
<th style="width: 150px;">日期</th>
<th style="width: 200px;">LIS分组名称</th>
<th style="width: 120px;">采血管</th>
<th style="width: 300px;">备注</th>
<th style="width: 150px;">操作</th>
</tr>
</thead>
<tbody>
<tr
v-for="(item, index) in tableData"
:key="item.id || index"
:class="{ 'editing-row': item.editing }"
>
<td>{{ index + 1 }}</td>
<td>
<template v-if="item.editing">
<input
type="text"
v-model="item.healthInstitution"
placeholder="请输入卫生机构"
:class="{ 'error-input': item.errors?.healthInstitution }"
>
<span v-if="item.errors?.healthInstitution" class="error-message">{{ item.errors.healthInstitution }}</span>
</template>
<template v-else>
{{ item.healthInstitution }}
</template>
</td>
<td>
<template v-if="item.editing">
<input type="text" v-model="item.date" disabled>
</template>
<template v-else>
{{ item.date }}
</template>
</td>
<td>
<template v-if="item.editing">
<input
type="text"
v-model="item.lisGroupName"
placeholder="请输入分组名称"
:class="{ 'error-input': item.errors?.lisGroupName }"
>
<span v-if="item.errors?.lisGroupName" class="error-message">{{ item.errors.lisGroupName }}</span>
</template>
<template v-else>
{{ item.lisGroupName }}
</template>
</td>
<td>
<template v-if="item.editing">
<select
v-model="item.bloodCollectionTube"
:class="{ 'error-input': item.errors?.bloodCollectionTube }"
>
<option value="">请选择采血管</option>
<option v-for="tube in bloodTubeOptions" :key="tube" :value="tube">
{{ tube }}
</option>
</select>
<span v-if="item.errors?.bloodCollectionTube" class="error-message">{{ item.errors.bloodCollectionTube }}</span>
</template>
<template v-else>
{{ item.bloodCollectionTube }}
</template>
</td>
<td>
<template v-if="item.editing">
<input type="text" v-model="item.remark" placeholder="请输入备注信息">
</template>
<template v-else>
{{ item.remark || '' }}
</template>
</td>
<td>
<div class="actions">
<template v-if="!item.editing">
<button class="btn btn-edit" @click="startEdit(item)"></button>
<button class="btn btn-primary" @click="addRow">+</button>
<button class="btn btn-delete" @click="deleteRow(index)">🗑</button>
</template>
<template v-else>
<button class="btn btn-confirm" @click="confirmEdit(item)"></button>
<button class="btn btn-cancel" @click="cancelEdit(item)">×</button>
</template>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<!-- 分页区域 -->
<div class="pagination">
<button class="pagination-btn"></button>
<span>1</span>
<button class="pagination-btn"></button>
</div>
</div>
</template>
<script>
import { ref, reactive, computed, onMounted, onBeforeUnmount } from 'vue'
import { listLisGroup, addLisGroup, updateLisGroup, delLisGroup } from '@/api/system/checkType'
import { getDicts } from "@/api/system/dict/data";
import axios from 'axios'
export default {
name: 'LisGroupMaintain',
setup() {
// 加载状态
const loading = ref(false)
// 采血管选项
const bloodTubeOptions = ref([]);
// 加载采血管颜色字典数据
const loadBloodTubeDict = async () => {
try {
const response = await getDicts('test_the_color_of_the_blood_collection_tube');
if (response.code === 200 && response.data) {
// 根据实际返回数据格式调整
bloodTubeOptions.value = response.data.map(item => item.label || item.dictLabel);
}
} catch (error) {
console.error('获取采血管颜色字典失败:', error);
// 如果字典获取失败,使用默认选项作为备选
bloodTubeOptions.value = ['黄管', '紫管', '蓝管'];
}
};
// 分页相关数据
const currentPage = ref(1)
const pageSize = ref(10)
const totalItems = ref(2) // 总数据量,实际应用中应该从后端获取
// 总页数
const totalPages = computed(() => {
return Math.ceil(totalItems.value / pageSize.value)
})
// 表格数据
const tableData = reactive([])
// 获取当前日期
const getCurrentDate = () => {
const date = new Date()
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`
}
// 加载LIS分组数据
const loadLisGroups = async () => {
// 确保采血管字典数据已加载
if (bloodTubeOptions.value.length === 0) {
await loadBloodTubeDict();
}
try {
loading.value = true
// 构建查询参数
const query = {
pageNum: currentPage.value,
pageSize: pageSize.value
}
console.log('准备调用接口,查询参数:', query)
// 调用接口获取数据
// 注意根据checkType.js中的定义这个接口使用GET方法和params参数
const response = await listLisGroup(query)
console.log('接口返回结果类型:', typeof response)
console.log('接口返回结果:', response)
console.log('响应是否包含code字段:', response && 'code' in response)
console.log('响应是否包含data字段:', response && 'data' in response)
// 清空现有数据
tableData.splice(0, tableData.length)
totalItems.value = 0
// 适配可能的不同响应格式
let items = []
let total = 0
// 检查响应是否存在
if (response) {
// 处理标准响应格式
if (typeof response === 'object') {
// 检查是否是标准API响应格式 {code, data, msg}
if ('code' in response) {
console.log('响应包含code字段:', response.code)
// 成功状态码处理
if (response.code === 200 || response.code === '200' || response.code === 0) {
console.log('响应状态码为成功状态')
// 检查data字段
if ('data' in response) {
console.log('响应包含data字段数据类型:', typeof response.data)
// 格式1: {data: {rows: [], total: number}}
if (response.data && typeof response.data === 'object') {
// 处理双重嵌套格式 {data: {code, msg, data: []}}
if (response.data.data && (Array.isArray(response.data.data) || typeof response.data.data === 'object')) {
console.log('匹配到格式: 双重嵌套 data.data');
// 如果data.data是数组直接使用
if (Array.isArray(response.data.data)) {
items = response.data.data;
total = items.length;
console.log('双重嵌套格式1: data.data是数组数据量:', items.length);
}
// 如果data.data是对象检查是否有rows字段
else if (Array.isArray(response.data.data.rows)) {
items = response.data.data.rows;
total = response.data.data.total !== undefined ? response.data.data.total : items.length;
console.log('双重嵌套格式2: data.data包含rows数据量:', items.length, ',总数:', total);
}
}
// 标准格式检查
else if (Array.isArray(response.data.rows)) {
items = response.data.rows
total = response.data.total !== undefined ? response.data.total : items.length
console.log('匹配到格式1: response.data.rows数据量:', items.length, ',总数:', total)
}
// 格式2: {data: []}
else if (Array.isArray(response.data)) {
items = response.data
total = items.length
console.log('匹配到格式2: response.data直接是数组数据量:', items.length)
}
// 检查是否有其他可能的格式
else {
console.log('响应data不是预期格式详细数据:', response.data)
// 尝试将整个data对象作为单个条目处理有些API可能直接返回单个对象
if (response.data) {
items = [response.data]
total = 1
console.log('尝试将整个data对象作为单个条目处理')
}
}
}
} else {
console.log('响应不包含data字段')
}
} else {
// 非成功状态码
const errorMsg = response.msg || response.message || `请求失败,状态码: ${response.code}`
console.error('请求失败:', errorMsg)
showMessage(errorMsg, 'error')
}
}
// 格式3: 响应本身是一个对象但没有code字段可能是单个记录
else if (!Array.isArray(response)) {
console.log('响应是对象但没有code字段尝试作为单个记录处理')
items = [response]
total = 1
}
}
// 格式4: 响应本身是数组
if (Array.isArray(response)) {
items = response
total = items.length
console.log('匹配到格式4: 响应本身是数组,数据量:', items.length)
}
// 记录最终解析到的数据量
console.log('最终解析到的数据量:', items.length, ',总数:', total)
} else {
console.error('接口返回空数据')
showMessage('获取LIS分组数据失败服务器返回空响应', 'error')
}
// 处理获取到的数据
if (items && items.length > 0) {
// 处理每条数据,确保字段正确映射
items.forEach((item, index) => {
// 确保item是对象类型
if (typeof item === 'object' && item !== null) {
console.log(`处理记录 ${index + 1} 原始数据:`, item);
// 创建格式化后的对象,确保字段存在
// 根据网络响应截图更正字段映射关系
const formattedItem = {
id: item.id || `temp_${Date.now()}_${index}`, // 确保有ID
// 更正字段映射hospital -> healthInstitution
healthInstitution: item.hospital || item.org || item.healthInstitution || '',
// 优先使用date字段
date: item.date || item.createTime || item.createDate || '',
// 更正字段映射groupName -> lisGroupName
lisGroupName: item.groupName || item.name || item.lisGroupName || '',
// 更正字段映射tube -> bloodCollectionTube
bloodCollectionTube: item.tube || item.property || item.bloodCollectionTube || item.bloodTube || '',
remark: item.remark || item.note || '',
editing: false,
// 保留原始对象的所有其他属性
...item
};
tableData.push(formattedItem);
console.log(`处理记录 ${index + 1} 格式化后数据:`, {
id: formattedItem.id,
healthInstitution: formattedItem.healthInstitution,
date: formattedItem.date,
lisGroupName: formattedItem.lisGroupName,
bloodCollectionTube: formattedItem.bloodCollectionTube,
remark: formattedItem.remark
});
} else {
console.warn(`记录 ${index + 1} 不是有效对象,跳过处理:`, item);
}
});
totalItems.value = total;
console.log('数据加载完成,表格显示', tableData.length, '条记录,总数:', totalItems.value);
} else {
console.log('未获取到有效数据,表格为空');
}
} catch (error) {
// 详细的错误信息记录
console.error('加载LIS分组数据异常:', error)
// 提取更详细的错误信息
let errorMessage = '加载LIS分组数据失败请稍后重试'
if (error.response) {
// 服务器响应了但状态码不是2xx
console.error('HTTP错误状态:', error.response.status)
console.error('HTTP错误响应体:', error.response.data)
if (error.response.data) {
errorMessage = error.response.data.msg ||
error.response.data.message ||
error.response.data.error ||
`服务器错误 (${error.response.status})`
} else {
errorMessage = `服务器错误 (${error.response.status})`
}
// 额外记录响应体详情便于调试
if (typeof error.response.data === 'object') {
console.error('响应体详细结构:', JSON.stringify(error.response.data, null, 2))
}
} else if (error.request) {
// 请求已发出,但未收到响应
console.error('请求已发送但未收到响应:', error.request)
errorMessage = '网络错误,服务器未响应,请检查网络连接'
} else if (error.message) {
// 请求配置出错
console.error('请求配置错误:', error.message)
errorMessage = error.message
} else {
console.error('未知错误类型:', typeof error)
}
// 显示错误信息
showMessage(errorMessage, 'error')
// 确保表格状态正确
console.log('异常处理后表格状态:', {
tableDataLength: tableData.length,
totalItems: totalItems.value,
currentPage: currentPage.value
})
} finally {
loading.value = false
console.log('数据加载操作完成loading状态已更新为false')
console.log('最终表格数据量:', tableData.length, ',总数:', totalItems.value)
}
}
// 开始编辑
const startEdit = (item) => {
// 存储原始数据,用于取消操作
item.originalData = { ...item }
item.editing = true
}
// 验证数据
const validateData = (item) => {
const errors = {}
// 清除之前的错误信息
delete item.errors
// 验证卫生机构
if (!item.healthInstitution || item.healthInstitution.trim() === '') {
errors.healthInstitution = '卫生机构不能为空'
} else if (item.healthInstitution.length > 100) {
errors.healthInstitution = '卫生机构名称不能超过100个字符'
}
// 验证LIS分组名称
if (!item.lisGroupName || item.lisGroupName.trim() === '') {
errors.lisGroupName = 'LIS分组名称不能为空'
} else if (item.lisGroupName.length > 50) {
errors.lisGroupName = 'LIS分组名称不能超过50个字符'
}
// 验证采血管
if (!item.bloodCollectionTube) {
errors.bloodCollectionTube = '请选择采血管'
}
// 验证备注长度
if (item.remark && item.remark.length > 200) {
errors.remark = '备注信息不能超过200个字符'
}
if (Object.keys(errors).length > 0) {
item.errors = errors
return false
}
return true
}
// 显示提示信息
const showMessage = (message, type = 'success') => {
// 在实际项目中这里可以使用Element Plus或其他UI库的消息组件
// 这里为了简单起见使用浏览器的alert但添加了类型标识
if (type === 'error') {
console.error(message)
alert(`错误: ${message}`)
} else {
console.log(message)
// 可以使用更友好的提示方式这里暂时注释掉alert以避免频繁弹窗
// alert(message)
}
}
// 确认编辑
const confirmEdit = async (item) => {
// 验证数据
if (!validateData(item)) {
showMessage('请检查并修正错误信息', 'error')
return
}
// 检查是否有重复的分组名称(在同一个卫生机构内)
const duplicate = tableData.find(data =>
data.id !== item.id &&
data.healthInstitution === item.healthInstitution &&
data.lisGroupName === item.lisGroupName
)
if (duplicate) {
if (!item.errors) item.errors = {}
item.errors.lisGroupName = '该分组名称已存在'
showMessage('分组名称重复,请修改', 'error')
return
}
try {
loading.value = true
// 准备提交数据(使用后端期望的字段名)
const submitData = {
id: item.id,
hospital: item.healthInstitution, // 前端字段映射到后端字段
date: item.date,
groupName: item.lisGroupName, // 前端字段映射到后端字段
tube: item.bloodCollectionTube, // 前端字段映射到后端字段
remark: item.remark
}
let response
// 判断是新增还是修改
if (item.isNew) {
// 新增
response = await addLisGroup(submitData)
} else {
// 修改
response = await updateLisGroup(submitData)
}
// 处理响应
if (response.code === 200) {
// 保存编辑
item.editing = false
delete item.originalData
delete item.errors
// 先检查是否是新增记录再删除isNew属性
const isNewRecord = item.isNew
delete item.isNew
showMessage('保存成功')
// 如果是新增,重新加载数据以确保数据一致性
if (isNewRecord) {
loadLisGroups()
}
} else {
showMessage(`保存失败: ${response.msg || '未知错误'}`, 'error')
}
} catch (error) {
console.error('保存LIS分组数据失败:', error)
showMessage(`保存失败: ${error.message || '未知错误'}`, 'error')
} finally {
loading.value = false
}
}
// 取消编辑
const cancelEdit = (item) => {
try {
if (item.isNew) {
// 如果是新增的行,从数组中移除
const index = tableData.findIndex(row => row.id === item.id)
if (index > -1) {
tableData.splice(index, 1)
// 更新总数
if (totalItems.value > 0) {
totalItems.value--
}
}
} else if (item.originalData) {
// 恢复原始数据
Object.assign(item, item.originalData)
delete item.originalData
item.editing = false
} else {
item.editing = false
}
} catch (error) {
console.error('取消编辑失败:', error)
showMessage('取消编辑失败', 'error')
}
}
// 添加新行
const addRow = () => {
// 检查是否已有正在编辑的行
const editingRow = tableData.find(item => item.editing)
if (editingRow) {
showMessage('请先完成当前行的编辑', 'error')
return
}
const newId = String(Math.max(...tableData.map(item => parseInt(item.id) || 0), 0) + 1)
tableData.push({
id: newId,
healthInstitution: '', // 空默认值
date: getCurrentDate(), // 默认当前系统时间
lisGroupName: '',
bloodCollectionTube: '',
remark: '',
editing: true,
errors: null,
isNew: true // 标记为新记录
})
showMessage('请填写新记录信息')
}
// 删除行
const deleteRow = async (index) => {
const item = tableData[index]
// 检查是否正在编辑
if (item.editing) {
showMessage('请先完成或取消编辑', 'error')
return
}
if (confirm(`确定要删除"${item.lisGroupName}"这条记录吗?`)) {
try {
loading.value = true
// 如果是新添加的记录,直接从数组中移除
if (item.isNew) {
tableData.splice(index, 1)
showMessage('删除成功')
totalItems.value--
} else {
// 调用API删除
const response = await delLisGroup(item.id)
if (response.code === 200) {
tableData.splice(index, 1)
showMessage('删除成功')
// 更新总数
totalItems.value--
} else {
showMessage(`删除失败: ${response.msg || '未知错误'}`, 'error')
}
}
} catch (error) {
console.error('删除LIS分组数据失败:', error)
showMessage(`删除失败: ${error.message || '未知错误'}`, 'error')
} finally {
loading.value = false
}
}
}
// 分页方法
const prevPage = () => {
if (currentPage.value > 1) {
currentPage.value--
// 调用加载数据方法
loadLisGroups()
}
}
const nextPage = () => {
if (currentPage.value < totalPages.value) {
currentPage.value++
// 调用加载数据方法
loadLisGroups()
}
}
const goToPage = (page) => {
if (page >= 1 && page <= totalPages.value) {
currentPage.value = page
// 调用加载数据方法
loadLisGroups()
}
}
// 组件挂载时加载数据
onMounted(() => {
// 加载采血管字典数据
loadBloodTubeDict();
// 加载表格数据
loadLisGroups()
})
return {
tableData,
bloodTubeOptions,
startEdit,
confirmEdit,
cancelEdit,
addRow,
deleteRow,
currentPage,
totalPages,
prevPage,
nextPage,
goToPage,
loading
}
}
}
</script>
<style scoped>
.lis-group-maintain {
padding: 20px;
min-height: 100vh;
}
.header {
height: 56px;
border-bottom: 1px solid #e8e8e8;
margin-bottom: 20px;
display: flex;
align-items: center;
}
.header h1 {
font-size: 18px;
font-weight: 500;
color: #333;
margin: 0;
}
.table-container {
margin-bottom: 20px;
overflow-x: auto;
border: 1px solid #e8e8e8;
border-radius: 2px;
}
.data-table {
width: 100%;
border-collapse: collapse;
text-align: left;
background-color: #fff;
}
.data-table th,
.data-table td {
padding: 12px;
border: 1px solid #e8e8e8;
word-break: break-all;
vertical-align: middle;
}
.data-table th {
background-color: #fafafa;
font-weight: 500;
}
.editing-row {
background-color: #f0f8ff;
}
.actions {
white-space: nowrap;
}
.pagination-section {
height: 48px;
display: flex;
justify-content: center;
align-items: center;
}
/* 分页样式 */
.pagination {
display: flex;
justify-content: flex-end;
align-items: center;
padding: 16px 0;
margin-top: 8px;
}
.pagination span {
font-size: 14px;
margin: 0 16px;
}
.pagination-btn {
background: none;
border: 1px solid #D9D9D9;
border-radius: 4px;
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.2s ease;
}
.pagination-btn:hover {
border-color: #1890FF;
color: #1890FF;
}
.pagination-btn:disabled {
cursor: not-allowed;
opacity: 0.5;
}
.pagination-number.active {
background-color: #1890ff;
color: #fff;
border-color: #1890ff;
}
.pagination-number.active:hover {
background-color: #40a9ff;
border-color: #40a9ff;
color: #fff;
}
.btn {
width: 24px;
height: 24px;
padding: 0;
margin-right: 5px;
border: 1px solid #d9d9d9;
background-color: #fff;
cursor: pointer;
border-radius: 4px;
font-size: 12px;
display: inline-flex;
align-items: center;
justify-content: center;
}
.btn:hover {
border-color: #40a9ff;
color: #40a9ff;
}
.btn-primary {
background-color: #1890ff;
color: #fff;
border-color: #1890ff;
}
.btn-primary:hover {
background-color: #40a9ff;
border-color: #40a9ff;
color: #fff;
}
.btn-confirm {
background-color: #52c41a;
color: #fff;
border-color: #52c41a;
}
.btn-confirm:hover {
background-color: #73d13d;
border-color: #73d13d;
color: #fff;
}
.btn-cancel {
background-color: #f5f5f5;
color: #333;
border-color: #d9d9d9;
}
.btn-edit {
background-color: #faad14;
color: #fff;
border-color: #faad14;
}
.btn-edit:hover {
background-color: #ffc53d;
border-color: #ffc53d;
color: #fff;
}
.btn-delete {
background-color: #ff4d4f;
color: #fff;
border-color: #ff4d4f;
}
.btn-delete:hover {
background-color: #ff7875;
border-color: #ff7875;
color: #fff;
}
input, select {
width: 100%;
padding: 4px 6px;
border: 1px solid #d9d9d9;
border-radius: 2px;
box-sizing: border-box;
}
input:disabled {
background-color: #f5f5f5;
cursor: not-allowed;
}
/* 错误状态样式 */
.error-input {
border-color: #ff4d4f !important;
}
.error-input:focus {
border-color: #ff4d4f !important;
box-shadow: 0 0 0 2px rgba(255, 77, 79, 0.2) !important;
}
.error-message {
display: block;
font-size: 12px;
color: #ff4d4f;
margin-top: 2px;
line-height: 1.2;
}
/* 错误提示区域样式 */
.error-message-container {
padding: 12px 16px;
background-color: #fff2f0;
border: 1px solid #ffccc7;
border-radius: 2px;
margin-bottom: 16px;
}
.error-text {
color: #ff4d4f;
font-size: 14px;
}
/* 加载状态样式 */
.loading-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(255, 255, 255, 0.7);
display: flex;
align-items: center;
justify-content: center;
z-index: 10;
}
/* 确保页面容器相对定位,使加载遮罩正常工作 */
.lis-group-maintain {
position: relative;
}
.table-container {
overflow-x: auto;
border: 1px solid #e8e8e8;
border-radius: 4px;
margin-bottom: 16px;
}
.data-table {
width: 100%;
border-collapse: collapse;
}
.data-table th,
.data-table td {
padding: 12px 8px;
text-align: center;
border-bottom: 1px solid #e8e8e8;
}
.data-table th {
background-color: #fafafa;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
}
/* 响应式设计 */
@media (max-width: 768px) {
.lis-group-maintain {
padding: 10px;
}
.header h1 {
font-size: 16px;
}
.table-container {
border-radius: 0;
}
.data-table {
font-size: 12px;
min-width: 600px; /* 确保表格在小屏幕上可以横向滚动 */
}
.data-table th,
.data-table td {
padding: 8px;
text-align: center;
}
.btn {
width: 20px;
height: 20px;
font-size: 11px;
margin-right: 2px;
}
.pagination-btn {
width: 28px;
height: 28px;
font-size: 12px;
margin: 0 2px;
}
}
/* 平滑过渡效果 */
.btn,
.pagination-btn,
.editing-row {
transition: all 0.3s ease;
}
/* 美化输入框和选择框的焦点样式 */
input:focus,
select:focus {
outline: none;
border-color: #40a9ff;
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
}
</style>

View File

@@ -19,7 +19,7 @@ export default defineConfig (({mode, command}) => {
// 部署生产环境和开发环境下的URL。 // 部署生产环境和开发环境下的URL。
// 默认情况下vite 会假设你的应用是被部署在一个域名的根路径上 // 默认情况下vite 会假设你的应用是被部署在一个域名的根路径上
// 例如 https://www.openHIS.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.openhis.vip/admin/,则设置 baseUrl 为 /admin/。 // 例如 https://www.openHIS.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.openhis.vip/admin/,则设置 baseUrl 为 /admin/。
base: VITE_APP_ENV === 'production' ? '/' : '/', base: VITE_APP_ENV === 'prod' ? '/' : '/',
plugins: createVitePlugins(env, command === 'build'), plugins: createVitePlugins(env, command === 'build'),
resolve: { resolve: {
// https://cn.vitejs.dev/config/#resolve-alias // https://cn.vitejs.dev/config/#resolve-alias
@@ -41,10 +41,6 @@ export default defineConfig (({mode, command}) => {
// https://cn.vitejs.dev/config/#server-proxy // https://cn.vitejs.dev/config/#server-proxy
'/dev-api': { '/dev-api': {
target: 'http://localhost:18080/openhis', target: 'http://localhost:18080/openhis',
// target: 'http://192.168.31.30:18080/openhis', // zwh
// target: 'http://192.168.31.50:18080/openhis', // wh
// target: 'http://192.168.31.190:18080/openhis', // yangmo
// target: 'http://60.188.247.175:18080/openhis',// 公网
changeOrigin: true, changeOrigin: true,
rewrite: p => p.replace(/^\/dev-api/, ''), rewrite: p => p.replace(/^\/dev-api/, ''),
}, },
@@ -53,13 +49,13 @@ export default defineConfig (({mode, command}) => {
changeOrigin: true, changeOrigin: true,
rewrite: p => p.replace(/^\/ybplugin/, ''), rewrite: p => p.replace(/^\/ybplugin/, ''),
}, },
'/prod-api': { '/prd-api': {
target: 'http://localhost:18080/openhis', target: 'http://localhost:18082/openhis',
changeOrigin: true, changeOrigin: true,
rewrite: p => p.replace (/^\/prod-api/, ''), rewrite: p => p.replace(/^\/prd-api/, ''),
}, },
'/test-api': { '/test-api': {
target: 'http://localhost:18080/openhis', target: 'http://localhost:18081/openhis',
changeOrigin: true, changeOrigin: true,
rewrite: p => p.replace(/^\/test-api/, ''), rewrite: p => p.replace(/^\/test-api/, ''),
} }