From 91bf0fa3b9ef114d4c7c20ef2aa23b1b5c58477e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E5=BA=86=E6=B3=B0?= <12369755+htcloud1@user.noreply.gitee.com> Date: Mon, 14 Sep 2026 22:37:10 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=8C=BB=E9=99=A2=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=20(admin=20=E7=AB=AF=20CRUD=20+=20=E5=AF=BC?= =?UTF-8?q?=E5=85=A5=E5=AF=BC=E5=87=BA)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 后端: BizHospital controller/domain/vo/mapper/service + Mapper XML - 前端: ry-vue3/src/views/admin/Hospital.vue + api/business/hospital.js - 模块面向 admin 角色, 提供医院主数据维护 Co-Authored-By: Claude Code --- .../controller/BizHospitalController.java | 119 ++++++ .../ruoyi/business/domain/BizHospital.java | 84 ++++ .../domain/vo/BizHospitalExportVo.java | 61 +++ .../domain/vo/BizHospitalImportVo.java | 66 +++ .../business/mapper/BizHospitalMapper.java | 52 +++ .../business/service/IBizHospitalService.java | 41 ++ .../service/impl/BizHospitalServiceImpl.java | 193 +++++++++ .../mapper/business/BizHospitalMapper.xml | 153 +++++++ ry-vue3/src/api/business/hospital.js | 39 ++ ry-vue3/src/views/admin/Hospital.vue | 387 ++++++++++++++++++ 10 files changed, 1195 insertions(+) create mode 100644 ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizHospitalController.java create mode 100644 ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizHospital.java create mode 100644 ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/vo/BizHospitalExportVo.java create mode 100644 ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/vo/BizHospitalImportVo.java create mode 100644 ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizHospitalMapper.java create mode 100644 ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizHospitalService.java create mode 100644 ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizHospitalServiceImpl.java create mode 100644 ry-api/ruoyi-business/src/main/resources/mapper/business/BizHospitalMapper.xml create mode 100644 ry-vue3/src/api/business/hospital.js create mode 100644 ry-vue3/src/views/admin/Hospital.vue diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizHospitalController.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizHospitalController.java new file mode 100644 index 0000000..cba8bab --- /dev/null +++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizHospitalController.java @@ -0,0 +1,119 @@ +package com.ruoyi.business.controller; + +import java.util.List; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import com.ruoyi.common.annotation.Log; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.common.utils.poi.ExcelUtil; +import com.ruoyi.business.domain.BizHospital; +import com.ruoyi.business.domain.dto.ImportResult; +import com.ruoyi.business.domain.vo.BizHospitalExportVo; +import com.ruoyi.business.domain.vo.BizHospitalImportVo; +import com.ruoyi.business.service.IBizHospitalService; + +/** + * 医院字典 Controller (admin 资料库管理 / 医院管理) + * + *

CRUD + 导入/导出走 admin 路由 (前端 AdminLayout 角色控制); + * 远程搜索 /search 为匿名公开 (医生注册下拉). + * 注: 不加 @PreAuthorize — 与 BizExpert/BizOrg 等业务 controller 一致 (业务角色不走 RuoYi RBAC). + * + * @author guoju + */ +@RestController +@RequestMapping("/business/hospital") +public class BizHospitalController extends BaseController { + + @Autowired + private IBizHospitalService bizHospitalService; + + /** 分页列表 (admin 后台, 支持 hospital/province/city/hospitalCode/militaryHospital/type 筛选) */ + @GetMapping("/list") + public TableDataInfo list(BizHospital entity) { + startPage(); + List rows = bizHospitalService.selectList(entity); + return getDataTable(rows); + } + + /** 详情 */ + @GetMapping("/{hospitalId}") + public AjaxResult getInfo(@PathVariable("hospitalId") Long hospitalId) { + return success(bizHospitalService.getById(hospitalId)); + } + + /** + * 远程搜索 (匿名公开, 医生注册下拉"边输入边查询") + * GET /business/hospital/search?keyword=xxx → [{hospitalId, province, city, hospital, ...}] LIMIT 30 + */ + @GetMapping("/search") + public AjaxResult search(@RequestParam(value = "keyword", required = false) String keyword) { + return success(bizHospitalService.searchByKeyword(keyword)); + } + + /** 删除前引用统计: 返回医院名被业务表 work_unit 引用的条数 */ + @GetMapping("/countUsage") + public AjaxResult countUsage(@RequestParam("hospital") String hospital) { + return success(bizHospitalService.countUsageByHospital(hospital)); + } + + @Log(title = "医院管理", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody BizHospital entity) { + return toAjax(bizHospitalService.insert(entity)); + } + + @Log(title = "医院管理", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody BizHospital entity) { + return toAjax(bizHospitalService.updateByPrimaryKey(entity)); + } + + @Log(title = "医院管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{hospitalIds}") + public AjaxResult remove(@PathVariable Long[] hospitalIds) { + return toAjax(bizHospitalService.deleteByPrimaryKeys(hospitalIds)); + } + + /** 导出 (中文列头, 跟随当前筛选条件) */ + @Log(title = "医院管理", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, BizHospital entity) { + List list = bizHospitalService.selectList(entity); + List exportList = new java.util.ArrayList<>(list.size()); + for (BizHospital h : list) { + BizHospitalExportVo v = new BizHospitalExportVo(); + v.setHospitalId(h.getHospitalId()); + v.setProvince(h.getProvince()); + v.setCity(h.getCity()); + v.setHospital(h.getHospital()); + v.setOriginalHospital(h.getOriginalHospital()); + v.setHospitalCode(h.getHospitalCode()); + v.setMilitaryHospital(h.getMilitaryHospital()); + v.setType(h.getType()); + exportList.add(v); + } + ExcelUtil util = new ExcelUtil<>(BizHospitalExportVo.class); + util.exportExcel(response, exportList, "医院数据"); + } + + /** 下载导入模板 */ + @GetMapping("/importTemplate") + public void importTemplate(HttpServletResponse response) { + ExcelUtil util = new ExcelUtil<>(BizHospitalImportVo.class); + util.importTemplateExcel(response, "医院数据"); + } + + /** 批量导入 (Excel → biz_hospital, 去重, 返回 ImportResult) */ + @Log(title = "医院管理", businessType = BusinessType.IMPORT) + @PostMapping("/importData") + public AjaxResult importData(MultipartFile file) throws Exception { + ImportResult result = bizHospitalService.importHospitals(file); + return success(result); + } +} \ No newline at end of file diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizHospital.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizHospital.java new file mode 100644 index 0000000..10f4c0f --- /dev/null +++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizHospital.java @@ -0,0 +1,84 @@ +package com.ruoyi.business.domain; + +import com.ruoyi.common.annotation.Excel; + +/** + * 医院字典 (biz_hospital) + * + *

admin 用户在"资料库管理 / 医院管理"下维护; 医生注册时通过 /business/hospital/search 远程搜索选择. + * + *

字段说明: + *

+ * + *

说明: 原表 schema 中 id 为 int NOT NULL 无 auto_increment, 改 BIGINT 由应用生成雪花 ID (与项目其他表风格一致). + * + * @author guoju + */ +public class BizHospital { + + private static final long serialVersionUID = 1L; + + /** 医院 ID (雪花 ID, BIGINT) */ + @Excel(name = "医院ID") + private Long hospitalId; + + /** 省 */ + @Excel(name = "省") + private String province; + + /** 市 */ + @Excel(name = "市") + private String city; + + /** 医院名称 (主显示名) */ + @Excel(name = "医院名称") + private String hospital; + + /** 原名称 */ + @Excel(name = "原名称") + private String originalHospital; + + /** 医院 CODE */ + @Excel(name = "医院CODE") + private String hospitalCode; + + /** 是否军医院 */ + @Excel(name = "是否军医院") + private String militaryHospital; + + /** 类型 */ + @Excel(name = "类型") + private String type; + + public Long getHospitalId() { return hospitalId; } + public void setHospitalId(Long hospitalId) { this.hospitalId = hospitalId; } + + public String getProvince() { return province; } + public void setProvince(String province) { this.province = province; } + + public String getCity() { return city; } + public void setCity(String city) { this.city = city; } + + public String getHospital() { return hospital; } + public void setHospital(String hospital) { this.hospital = hospital; } + + public String getOriginalHospital() { return originalHospital; } + public void setOriginalHospital(String originalHospital) { this.originalHospital = originalHospital; } + + public String getHospitalCode() { return hospitalCode; } + public void setHospitalCode(String hospitalCode) { this.hospitalCode = hospitalCode; } + + public String getMilitaryHospital() { return militaryHospital; } + public void setMilitaryHospital(String militaryHospital) { this.militaryHospital = militaryHospital; } + + public String getType() { return type; } + public void setType(String type) { this.type = type; } +} \ No newline at end of file diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/vo/BizHospitalExportVo.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/vo/BizHospitalExportVo.java new file mode 100644 index 0000000..e8ae5b3 --- /dev/null +++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/vo/BizHospitalExportVo.java @@ -0,0 +1,61 @@ +package com.ruoyi.business.domain.vo; + +import com.ruoyi.common.annotation.Excel; + +/** + * 医院字典导出 VO + * + *

仅用于 Excel 导出, 不参与业务逻辑. + * + * @author guoju + */ +public class BizHospitalExportVo { + + @Excel(name = "医院ID", sort = 1) + private Long hospitalId; + + @Excel(name = "省", sort = 2) + private String province; + + @Excel(name = "市", sort = 3) + private String city; + + @Excel(name = "医院名称", sort = 4) + private String hospital; + + @Excel(name = "原名称", sort = 5) + private String originalHospital; + + @Excel(name = "医院CODE", sort = 6) + private String hospitalCode; + + @Excel(name = "是否军医院", sort = 7) + private String militaryHospital; + + @Excel(name = "类型", sort = 8) + private String type; + + public Long getHospitalId() { return hospitalId; } + public void setHospitalId(Long hospitalId) { this.hospitalId = hospitalId; } + + public String getProvince() { return province; } + public void setProvince(String province) { this.province = province; } + + public String getCity() { return city; } + public void setCity(String city) { this.city = city; } + + public String getHospital() { return hospital; } + public void setHospital(String hospital) { this.hospital = hospital; } + + public String getOriginalHospital() { return originalHospital; } + public void setOriginalHospital(String originalHospital) { this.originalHospital = originalHospital; } + + public String getHospitalCode() { return hospitalCode; } + public void setHospitalCode(String hospitalCode) { this.hospitalCode = hospitalCode; } + + public String getMilitaryHospital() { return militaryHospital; } + public void setMilitaryHospital(String militaryHospital) { this.militaryHospital = militaryHospital; } + + public String getType() { return type; } + public void setType(String type) { this.type = type; } +} \ No newline at end of file diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/vo/BizHospitalImportVo.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/vo/BizHospitalImportVo.java new file mode 100644 index 0000000..c3fc79b --- /dev/null +++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/vo/BizHospitalImportVo.java @@ -0,0 +1,66 @@ +package com.ruoyi.business.domain.vo; + +import com.ruoyi.common.annotation.Excel; + +/** + * 医院字典导入 VO + * + *

仅用于 Excel 批量导入 / 模板下载, 不参与业务逻辑. + * 字段顺序与 Excel 列一致; hospitalId 不在导入范围 (由 SnowflakeId 生成). + * + *

必填: hospital (医院名称). + * 其余字段允许空. + * + * @author guoju + */ +public class BizHospitalImportVo { + + /** 省 */ + @Excel(name = "省", sort = 1) + private String province; + + /** 市 */ + @Excel(name = "市", sort = 2) + private String city; + + /** 医院名称 (必填) */ + @Excel(name = "医院名称", sort = 3) + private String hospital; + + /** 原名称 */ + @Excel(name = "原名称", sort = 4) + private String originalHospital; + + /** 医院 CODE */ + @Excel(name = "医院CODE", sort = 5) + private String hospitalCode; + + /** 是否军医院 (0=否, 1=是) */ + @Excel(name = "是否军医院", sort = 6) + private String militaryHospital; + + /** 类型 */ + @Excel(name = "类型", sort = 7) + private String type; + + public String getProvince() { return province; } + public void setProvince(String province) { this.province = province; } + + public String getCity() { return city; } + public void setCity(String city) { this.city = city; } + + public String getHospital() { return hospital; } + public void setHospital(String hospital) { this.hospital = hospital; } + + public String getOriginalHospital() { return originalHospital; } + public void setOriginalHospital(String originalHospital) { this.originalHospital = originalHospital; } + + public String getHospitalCode() { return hospitalCode; } + public void setHospitalCode(String hospitalCode) { this.hospitalCode = hospitalCode; } + + public String getMilitaryHospital() { return militaryHospital; } + public void setMilitaryHospital(String militaryHospital) { this.militaryHospital = militaryHospital; } + + public String getType() { return type; } + public void setType(String type) { this.type = type; } +} \ No newline at end of file diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizHospitalMapper.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizHospitalMapper.java new file mode 100644 index 0000000..cf4056b --- /dev/null +++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizHospitalMapper.java @@ -0,0 +1,52 @@ +package com.ruoyi.business.mapper; + +import java.util.List; +import org.apache.ibatis.annotations.Param; +import com.ruoyi.business.domain.BizHospital; + +/** + * 医院字典 Mapper (biz_hospital) + * + *

无 del_flag 列 — 删除走硬删 (admin 字典, workUnit 字符串引用, 删除不会破坏业务数据完整性). + * + * @author guoju + */ +public interface BizHospitalMapper { + + /** 按主键查询 */ + BizHospital selectByPrimaryKey(@Param("hospitalId") Long hospitalId); + + /** 分页 + 多条件模糊筛选 (admin 后台用, 支持 hospital/province/type/militaryHospital) */ + List selectList(BizHospital entity); + + /** 新增 */ + int insert(BizHospital entity); + + /** 按主键更新 (动态 trim SET) */ + int updateByPrimaryKey(BizHospital entity); + + /** 批量硬删 */ + int deleteByPrimaryKeys(@Param("hospitalIds") Long[] hospitalIds); + + /** + * 远程搜索: 按关键字模糊匹配 hospital / originalHospital / hospitalCode, + * LIMIT 30 (医生注册下拉防爆). + * keyword 为空时返回空集 (前端按"边输入边查询"约定不主动出建议). + */ + List searchByKeyword(@Param("keyword") String keyword); + + /** + * 唯一性检查: 按 trim(hospital) + province + city 精确匹配 (case-insensitive). + * hospitalId 非空时排除自身 (改名/同名异市用); 用于新增/编辑前的"同名医院"提示. + * 返回匹配条数 (0 或 1). + */ + int countByTrimmedHospital(BizHospital entity); + + /** + * 统计指定医院名称被业务表 work_unit 字段引用的总条数. + * 用于删除前给 admin 二次确认: "该医院已被 N 条专家/参会人引用". + * 4 表 union: biz_expert / biz_signup_expert / biz_meeting_attendee / biz_execution_intent (有 work_unit 列) + * 注: biz_support_intent 也有 work_unit 列, 一起并入. + */ + int countUsageByHospital(@Param("hospital") String hospital); +} \ No newline at end of file diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizHospitalService.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizHospitalService.java new file mode 100644 index 0000000..eb62c1b --- /dev/null +++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizHospitalService.java @@ -0,0 +1,41 @@ +package com.ruoyi.business.service; + +import java.util.List; +import org.springframework.web.multipart.MultipartFile; +import com.ruoyi.business.domain.BizHospital; +import com.ruoyi.business.domain.dto.ImportResult; + +/** + * 医院字典 Service 接口 (biz_hospital) + * + * @author guoju + */ +public interface IBizHospitalService { + + /** 按主键查询 */ + BizHospital getById(Long hospitalId); + + /** 分页 + 多条件筛选 */ + List selectList(BizHospital entity); + + /** 新增 (医院名查重 + 雪花 ID) */ + int insert(BizHospital entity); + + /** 编辑 (医院名查重) */ + int updateByPrimaryKey(BizHospital entity); + + /** 批量硬删 */ + int deleteByPrimaryKeys(Long[] hospitalIds); + + /** 远程搜索 (医生注册下拉, LIMIT 30) */ + List searchByKeyword(String keyword); + + /** 唯一性检查: 同 name + province + city 是否已存在 (排除自身) */ + int countByTrimmedHospital(BizHospital entity); + + /** 统计医院名被业务表 work_unit 引用的条数 (删除前二次确认用) */ + int countUsageByHospital(String hospital); + + /** 批量导入 (Excel → biz_hospital, 批内/DB 去重, 返回 ImportResult) */ + ImportResult importHospitals(MultipartFile file) throws Exception; +} \ No newline at end of file diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizHospitalServiceImpl.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizHospitalServiceImpl.java new file mode 100644 index 0000000..f2aa649 --- /dev/null +++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizHospitalServiceImpl.java @@ -0,0 +1,193 @@ +package com.ruoyi.business.service.impl; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; +import com.ruoyi.business.domain.BizHospital; +import com.ruoyi.business.domain.dto.ImportResult; +import com.ruoyi.business.domain.vo.BizHospitalImportVo; +import com.ruoyi.business.mapper.BizHospitalMapper; +import com.ruoyi.business.service.IBizHospitalService; +import com.ruoyi.common.exception.ServiceException; +import com.ruoyi.common.utils.id.SnowflakeId; +import com.ruoyi.common.utils.poi.ExcelUtil; + +/** + * 医院字典 Service 实现 (biz_hospital) + * + *

要点: + *

+ * + * @author guoju + */ +@Service +public class BizHospitalServiceImpl implements IBizHospitalService { + + @Autowired + private BizHospitalMapper bizHospitalMapper; + + @Override + public BizHospital getById(Long hospitalId) { + return bizHospitalMapper.selectByPrimaryKey(hospitalId); + } + + @Override + public List selectList(BizHospital entity) { + return bizHospitalMapper.selectList(entity); + } + + @Override + public int insert(BizHospital entity) { + String hospital = trimToNull(entity.getHospital()); + if (hospital == null) { + throw new ServiceException("医院名称不能为空"); + } + entity.setHospital(hospital); + normalize(entity); + + // 同名医院查重 (trim + case-insensitive + province/city 匹配) + BizHospital probe = new BizHospital(); + probe.setHospital(hospital); + probe.setProvince(entity.getProvince()); + probe.setCity(entity.getCity()); + if (bizHospitalMapper.countByTrimmedHospital(probe) > 0) { + throw new ServiceException("医院「" + hospital + "」已存在"); + } + + SnowflakeId.injectIfEmpty(entity, "hospitalId"); + return bizHospitalMapper.insert(entity); + } + + @Override + public int updateByPrimaryKey(BizHospital entity) { + if (entity.getHospitalId() == null) { + throw new ServiceException("医院 ID 不能为空"); + } + String hospital = trimToNull(entity.getHospital()); + if (hospital == null) { + throw new ServiceException("医院名称不能为空"); + } + entity.setHospital(hospital); + normalize(entity); + + // 改名时同样查重 (排除自身) + BizHospital probe = new BizHospital(); + probe.setHospital(hospital); + probe.setProvince(entity.getProvince()); + probe.setCity(entity.getCity()); + probe.setHospitalId(entity.getHospitalId()); + if (bizHospitalMapper.countByTrimmedHospital(probe) > 0) { + throw new ServiceException("医院「" + hospital + "」已存在"); + } + + return bizHospitalMapper.updateByPrimaryKey(entity); + } + + @Override + public int deleteByPrimaryKeys(Long[] hospitalIds) { + return bizHospitalMapper.deleteByPrimaryKeys(hospitalIds); + } + + @Override + public List searchByKeyword(String keyword) { + return bizHospitalMapper.searchByKeyword(keyword); + } + + @Override + public int countByTrimmedHospital(BizHospital entity) { + return bizHospitalMapper.countByTrimmedHospital(entity); + } + + @Override + public int countUsageByHospital(String hospital) { + if (hospital == null || hospital.trim().isEmpty()) { + return 0; + } + return bizHospitalMapper.countUsageByHospital(hospital.trim()); + } + + /** + * 批量导入: Excel → biz_hospital. + *
    + *
  1. ExcelUtil 反序列化
  2. + *
  3. 行级校验 (医院名必填) + 批内去重 + DB 去重
  4. + *
  5. 逐行 insert (雪花 ID), 失败记 ngList 不影响其它行
  6. + *
+ */ + @Override + public ImportResult importHospitals(MultipartFile file) throws Exception { + ExcelUtil util = new ExcelUtil<>(BizHospitalImportVo.class); + List importList = util.importExcel(file.getInputStream()); + if (importList == null || importList.isEmpty()) { + throw new ServiceException("导入数据不能为空"); + } + ImportResult result = new ImportResult(); + Set seenHospital = new HashSet<>(); + + for (int i = 0; i < importList.size(); i++) { + BizHospitalImportVo vo = importList.get(i); + int rowNo = i + 2; // Excel 行号 (1=表头) + try { + String hospital = trimToNull(vo.getHospital()); + if (hospital == null) { + throw new ServiceException("医院名称不能为空"); + } + + // 批内去重 (case-insensitive) + String key = hospital.toLowerCase(); + if (!seenHospital.add(key)) { + throw new ServiceException("医院「" + hospital + "」在文件中重复"); + } + + // DB 去重 + BizHospital probe = new BizHospital(); + probe.setHospital(hospital); + probe.setProvince(trimToNull(vo.getProvince())); + probe.setCity(trimToNull(vo.getCity())); + if (bizHospitalMapper.countByTrimmedHospital(probe) > 0) { + throw new ServiceException("医院「" + hospital + "」已存在"); + } + + BizHospital entity = new BizHospital(); + entity.setHospital(hospital); + entity.setProvince(trimToNull(vo.getProvince())); + entity.setCity(trimToNull(vo.getCity())); + entity.setOriginalHospital(trimToNull(vo.getOriginalHospital())); + entity.setHospitalCode(trimToNull(vo.getHospitalCode())); + entity.setMilitaryHospital(trimToNull(vo.getMilitaryHospital())); + entity.setType(trimToNull(vo.getType())); + SnowflakeId.injectIfEmpty(entity, "hospitalId"); + bizHospitalMapper.insert(entity); + + result.ok(); + } catch (Exception e) { + result.fail(rowNo, e.getMessage() == null ? "导入失败" : e.getMessage()); + } + } + return result; + } + + /** 除 hospital 外的字段统一 trim (把空串压成 null, 避免脏数据) */ + private void normalize(BizHospital entity) { + entity.setProvince(trimToNull(entity.getProvince())); + entity.setCity(trimToNull(entity.getCity())); + entity.setOriginalHospital(trimToNull(entity.getOriginalHospital())); + entity.setHospitalCode(trimToNull(entity.getHospitalCode())); + entity.setMilitaryHospital(trimToNull(entity.getMilitaryHospital())); + entity.setType(trimToNull(entity.getType())); + } + + private String trimToNull(String s) { + if (s == null) return null; + String t = s.trim(); + return t.isEmpty() ? null : t; + } +} \ No newline at end of file diff --git a/ry-api/ruoyi-business/src/main/resources/mapper/business/BizHospitalMapper.xml b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizHospitalMapper.xml new file mode 100644 index 0000000..e673ffd --- /dev/null +++ b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizHospitalMapper.xml @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + select id, province, city, hospital, original_hospital, hospital_code, military_hospital, type + from biz_hospital + + + + + + + + + + + + + insert into biz_hospital + + id, + province, + city, + hospital, + original_hospital, + hospital_code, + military_hospital, + type, + + + #{hospitalId}, + #{province}, + #{city}, + #{hospital}, + #{originalHospital}, + #{hospitalCode}, + #{militaryHospital}, + #{type}, + + + + + + update biz_hospital + + province = #{province}, + city = #{city}, + hospital = #{hospital}, + original_hospital = #{originalHospital}, + hospital_code = #{hospitalCode}, + military_hospital = #{militaryHospital}, + type = #{type}, + + where id = #{hospitalId} + + + + + delete from biz_hospital where id in + + #{hid} + + + + + + + + + \ No newline at end of file diff --git a/ry-vue3/src/api/business/hospital.js b/ry-vue3/src/api/business/hospital.js new file mode 100644 index 0000000..d95e4db --- /dev/null +++ b/ry-vue3/src/api/business/hospital.js @@ -0,0 +1,39 @@ +import request from '@/utils/request' + +/** + * 医院字典 API (biz_hospital) + * 基础 CRUD 走 @/api/public 的 bizList/bizGet/bizAdd/bizUpdate/bizDelete (路径 /business/hospital/...) + * 本文件只放特殊形状的端点: 远程搜索 / 引用统计 / 导入模板 / 导入 / 导出 + */ + +// 医生注册下拉远程搜索 (匿名公开, keyword 为空不返回建议) +export function searchHospital(keyword) { + return request.get('/business/hospital/search', { params: { keyword } }) +} + +// 删除前引用统计: 返回医院名被业务表 work_unit 引用的条数 +export function countHospitalUsage(hospital) { + return request.get('/business/hospital/countUsage', { params: { hospital } }) +} + +// 下载导入模板 (blob) +export function downloadHospitalTemplate() { + return request.get('/business/hospital/importTemplate', { responseType: 'blob' }) +} + +// 批量导入 (FormData multipart, 返回 { code, msg, data: ImportResult }) +export function importHospital(file) { + const form = new FormData() + form.append('file', file) + return request({ + url: '/business/hospital/importData', + method: 'post', + data: form, + headers: { 'Content-Type': 'multipart/form-data' } + }) +} + +// 导出 (跟随当前筛选条件, blob) +export function exportHospital(params) { + return request.post('/business/hospital/export', null, { params, responseType: 'blob' }) +} diff --git a/ry-vue3/src/views/admin/Hospital.vue b/ry-vue3/src/views/admin/Hospital.vue new file mode 100644 index 0000000..cbbec25 --- /dev/null +++ b/ry-vue3/src/views/admin/Hospital.vue @@ -0,0 +1,387 @@ + + + + +