From b349acb4b47ccd173f01978c238bc0fd54d03268 Mon Sep 17 00:00:00 2001 From: haomingming Date: Wed, 16 Sep 2026 17:21:31 +0800 Subject: [PATCH] =?UTF-8?q?1=E3=80=81=E5=A2=9E=E5=8A=A0=E5=AF=BC=E5=87=BA?= =?UTF-8?q?=E8=8D=AF=E6=88=BF=E5=85=B3=E8=81=94=E5=8C=BB=E7=94=9F=E5=88=97?= =?UTF-8?q?=E8=A1=A8=E5=AF=BC=E5=87=BA=202=E3=80=81=E6=A3=80=E6=B5=8B?= =?UTF-8?q?=E5=88=B0=E6=9C=89=E7=BB=91=E5=AE=9A/=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E5=8C=BB=E7=94=9F=E6=97=B6=E7=9B=B4=E6=8E=A5=E6=8A=A5=E9=94=99?= =?UTF-8?q?=EF=BC=8C=E5=BC=BA=E5=88=B6=E8=A6=81=E6=B1=82=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E5=91=98=E5=85=88=E6=89=8B=E5=8A=A8=E5=A4=84=E7=90=86=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/controller/export.go | 48 ++++++++++++++++++++ api/dao/doctorPharmacy.go | 95 +++++++++++++++++++++++++++++++++++++++ api/requests/pharmacy.go | 24 +++++++--- api/router/router.go | 13 ++++++ api/service/export.go | 87 +++++++++++++++++++++++++++++++++++ api/service/pharmacy.go | 37 +++++++++++++++ 6 files changed, 297 insertions(+), 7 deletions(-) diff --git a/api/controller/export.go b/api/controller/export.go index b77099f..249d3ce 100644 --- a/api/controller/export.go +++ b/api/controller/export.go @@ -781,3 +781,51 @@ func (r *Export) OrderService(c *gin.Context) { responses.OkWithData(ossAddress, c) } + +// PharmacyDoctor 药房关联医生 +func (r *Export) PharmacyDoctor(c *gin.Context) { + pharmacyRequest := requests.PharmacyRequest{} + req := pharmacyRequest.PharmacyDoctorExportList + if err := c.ShouldBind(&req); err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + // 参数验证 + if err := global.Validate.Struct(req); err != nil { + responses.FailWithMessage(utils.Translate(err), c) + return + } + + // 获取数据 + doctorPharmacyDao := dao.DoctorPharmacyDao{} + list, err := doctorPharmacyDao.GetPharmacyDoctorExportListSearch(req) + if err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + // 业务处理 + exportService := service.ExportService{} + ossAddress, err := exportService.PharmacyDoctor(list) + if err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + // 获取当前登陆用户id + userId := c.GetInt64("UserId") + if userId != 0 { + // 记录日志 + logExport := &model.LogExport{ + AdminUserId: userId, + ExportModule: "药房关联医生", + ExportFile: utils.RemoveOssDomain(ossAddress), + } + + logExportDao := dao.LogExportDao{} + _, _ = logExportDao.AddLogExportUnTransaction(logExport) + } + + responses.OkWithData(ossAddress, c) +} diff --git a/api/dao/doctorPharmacy.go b/api/dao/doctorPharmacy.go index 968bed4..46a62ad 100644 --- a/api/dao/doctorPharmacy.go +++ b/api/dao/doctorPharmacy.go @@ -1,6 +1,10 @@ package dao import ( + "errors" + "strconv" + "strings" + "gorm.io/gorm" "hospital-admin-api/api/model" "hospital-admin-api/api/requests" @@ -168,3 +172,94 @@ func (r *DoctorPharmacyDao) GetPharmacyDoctorListByPharmacyId(pharmacyId int64) } return m, nil } + +// GetDoctorPharmacyCountsByPharmacyId 获取药房绑定的医生数量(有效绑定数、设为默认药房数) +func (r *DoctorPharmacyDao) GetDoctorPharmacyCountsByPharmacyId(pharmacyId int64) (totalCount int64, defaultCount int64, err error) { + err = global.Db.Model(&model.DoctorPharmacy{}). + Where("pharmacy_id = ? AND status = 1", pharmacyId). + Count(&totalCount).Error + if err != nil { + return 0, 0, err + } + + err = global.Db.Model(&model.DoctorPharmacy{}). + Where("pharmacy_id = ? AND status = 1 AND is_default = 1", pharmacyId). + Count(&defaultCount).Error + if err != nil { + return 0, 0, err + } + + return totalCount, defaultCount, nil +} + +// GetPharmacyDoctorExportListSearch 获取药房关联医生列表-导出 +func (r *DoctorPharmacyDao) GetPharmacyDoctorExportListSearch(req requests.PharmacyDoctorExportList) (m []*model.DoctorPharmacy, err error) { + query := global.Db.Model(&model.DoctorPharmacy{}). + Where("gdxz_doctor_pharmacy.status = 1") + + // 药房id过滤 + if req.PharmacyId != "" { + pharmacyId, _ := strconv.ParseInt(req.PharmacyId, 10, 64) + if pharmacyId >= 0 { + query = query.Where("gdxz_doctor_pharmacy.pharmacy_id = ?", pharmacyId) + } + } + + // 1:当前搜索数据 + if req.Type == 1 { + needJoinDoctor := req.DoctorName != "" || req.Mobile != "" + if needJoinDoctor { + query = query.Joins("JOIN gdxz_user_doctor ON gdxz_user_doctor.doctor_id = gdxz_doctor_pharmacy.doctor_id") + if req.DoctorName != "" { + query = query.Where("gdxz_user_doctor.user_name LIKE ?", "%"+req.DoctorName+"%") + } + if req.Mobile != "" { + query = query.Joins("JOIN gdxz_user ON gdxz_user.user_id = gdxz_user_doctor.user_id"). + Where("gdxz_user.mobile LIKE ?", "%"+req.Mobile+"%") + } + } + } + + // 2:当前选中数据 + if req.Type == 2 { + if req.Id == "" { + return nil, errors.New("未提供需导出数据编号") + } + id := strings.Split(req.Id, ",") + query = query.Where("gdxz_doctor_pharmacy.doctor_pharmacy_id IN (?) OR gdxz_doctor_pharmacy.doctor_id IN (?)", id, id) + } + + // 3:全部数据(无额外搜索条件) + + err = query.Order("gdxz_doctor_pharmacy.is_default desc, gdxz_doctor_pharmacy.created_at desc"). + Preload("Pharmacy"). + Preload("UserDoctor.User"). + Preload("UserDoctor.Hospital"). + Find(&m).Error + if err != nil { + return nil, err + } + + // GORM 在外键为 0 时会自动跳过 Preload,因此针对未能预加载的记录进行兜底补全 + var zeroPharmacy *model.Pharmacy + for _, dp := range m { + if dp.Pharmacy == nil { + if dp.PharmacyId == 0 { + if zeroPharmacy == nil { + var ph model.Pharmacy + if err := global.Db.Where("pharmacy_id = 0").First(&ph).Error; err == nil { + zeroPharmacy = &ph + } + } + dp.Pharmacy = zeroPharmacy + } else { + var ph model.Pharmacy + if err := global.Db.Where("pharmacy_id = ?", dp.PharmacyId).First(&ph).Error; err == nil { + dp.Pharmacy = &ph + } + } + } + } + + return m, nil +} diff --git a/api/requests/pharmacy.go b/api/requests/pharmacy.go index d51d6b3..0713e03 100644 --- a/api/requests/pharmacy.go +++ b/api/requests/pharmacy.go @@ -1,13 +1,23 @@ package requests type PharmacyRequest struct { - GetPharmacyList // 获取药房列表 - GetPharmacyPage // 获取药房列表-分页 - AddPharmacy // 新增药房 - PutPharmacy // 修改药房 - PutPharmacyStatus // 修改药房状态 - GetPharmacyDoctorPage // 药房绑定的医生列表-分页 - GetPharmacyDoctorList // 药房绑定的医生列表 + GetPharmacyList // 获取药房列表 + GetPharmacyPage // 获取药房列表-分页 + AddPharmacy // 新增药房 + PutPharmacy // 修改药房 + PutPharmacyStatus // 修改药房状态 + GetPharmacyDoctorPage // 药房绑定的医生列表-分页 + GetPharmacyDoctorList // 药房绑定的医生列表 + PharmacyDoctorExportList // 药房关联医生-导出 +} + +// PharmacyDoctorExportList 药房关联医生-导出 +type PharmacyDoctorExportList struct { + Type int `json:"type" form:"type" label:"类型" validate:"required,oneof=1 2 3"` // 1:当前搜索数据 2:当前选择数据 3:全部数据 + Id string `json:"id" form:"id" label:"id"` // 选择数据的id(doctor_pharmacy_id或doctor_id),逗号分隔 + PharmacyId string `json:"pharmacy_id" form:"pharmacy_id" label:"药房id"` // 药房id + DoctorName string `json:"doctor_name" form:"doctor_name" label:"医生姓名"` // 医生姓名 + Mobile string `json:"mobile" form:"mobile" label:"手机号"` // 手机号 } // GetPharmacyDoctorPage 药房绑定的医生列表-分页 diff --git a/api/router/router.go b/api/router/router.go index 62b3914..206cfe3 100644 --- a/api/router/router.go +++ b/api/router/router.go @@ -391,6 +391,9 @@ func privateRouter(r *gin.Engine, api controller.Api) { // 设置医生的默认药房 doctorPharmacyGroup.PUT("/default/:id", api.DoctorPharmacy.SetDefaultDoctorPharmacy) doctorPharmacyGroup.PUT("/default", api.DoctorPharmacy.SetDefaultDoctorPharmacyPut) + + // 药房关联医生-导出 + doctorPharmacyGroup.POST("/export", api.Export.PharmacyDoctor) } // 身份审核列表 @@ -809,6 +812,13 @@ func privateRouter(r *gin.Engine, api controller.Api) { // 系统药品 productGroup.POST("", api.Export.Product) } + + // 药房 + pharmacyGroup := exportGroup.Group("/pharmacy") + { + // 药房关联医生 + pharmacyGroup.POST("/doctor", api.Export.PharmacyDoctor) + } } // 商品管理 @@ -943,6 +953,9 @@ func privateRouter(r *gin.Engine, api controller.Api) { // 药房绑定的医生列表 pharmacyGroup.GET("/doctor/:pharmacy_id", api.Pharmacy.GetPharmacyDoctorList) + + // 药房关联医生-导出 + pharmacyGroup.POST("/doctor/export", api.Export.PharmacyDoctor) } // 科普分类管理 diff --git a/api/service/export.go b/api/service/export.go index eb9d9cf..af5cf09 100644 --- a/api/service/export.go +++ b/api/service/export.go @@ -380,6 +380,21 @@ type ProductData struct { CreatedAt string // 创建时间 } +// PharmacyDoctorData 药房关联医生 +type PharmacyDoctorData struct { + PharmacyName string // 药房名称 + PharmacyCode string // 药房代码 + DoctorName string // 医生姓名 + Mobile string // 手机号 + DoctorTitle string // 医生职称 + HospitalName string // 医院名称 + DepartmentCustomName string // 科室名称 + DepartmentCustomMobile string // 科室电话 + IsDefault string // 是否默认药房(0:否 1:是) + Status string // 状态(0:禁用 1:正常) + CreatedAt string // 关联时间 +} + // DoctorWithdrawal 提现记录 func (r *ExportService) DoctorWithdrawal(doctorWithdrawals []*model.DoctorWithdrawal) (string, error) { header := []utils.HeaderCellData{ @@ -2052,3 +2067,75 @@ func (r *ExportService) Product(d []*model.Product) (string, error) { ossPath = utils.AddOssDomain("/" + ossPath) return ossPath, nil } + +// PharmacyDoctor 药房关联医生 +func (r *ExportService) PharmacyDoctor(d []*model.DoctorPharmacy) (string, error) { + header := []utils.HeaderCellData{ + {Value: "药房名称", CellType: "string", NumberFmt: "", ColWidth: 25}, + {Value: "药房代码", CellType: "string", NumberFmt: "", ColWidth: 18}, + {Value: "医生姓名", CellType: "string", NumberFmt: "", ColWidth: 18}, + {Value: "手机号", CellType: "string", NumberFmt: "", ColWidth: 18}, + {Value: "医生职称", CellType: "string", NumberFmt: "", ColWidth: 18}, + {Value: "医院名称", CellType: "string", NumberFmt: "", ColWidth: 30}, + {Value: "科室名称", CellType: "string", NumberFmt: "", ColWidth: 20}, + {Value: "科室电话", CellType: "string", NumberFmt: "", ColWidth: 18}, + {Value: "是否默认药房", CellType: "string", NumberFmt: "", ColWidth: 18}, + {Value: "状态", CellType: "string", NumberFmt: "", ColWidth: 15}, + {Value: "关联时间", CellType: "date", NumberFmt: "yyyy-mm-dd hh:mm:ss", ColWidth: 30}, + } + + var dataSlice []interface{} + for _, v := range d { + data := PharmacyDoctorData{ + IsDefault: utils.IsDefaultToString(v.IsDefault), + Status: "正常", + } + if v.Status == 0 { + data.Status = "禁用" + } + + if v.Pharmacy != nil { + data.PharmacyName = v.Pharmacy.PharmacyName + data.PharmacyCode = v.Pharmacy.PharmacyCode + } + + if v.UserDoctor != nil { + data.DoctorName = v.UserDoctor.UserName + data.DoctorTitle = utils.DoctorTitleToString(v.UserDoctor.DoctorTitle) + data.DepartmentCustomName = v.UserDoctor.DepartmentCustomName + data.DepartmentCustomMobile = v.UserDoctor.DepartmentCustomMobile + if v.UserDoctor.Hospital != nil { + data.HospitalName = v.UserDoctor.Hospital.HospitalName + } + if v.UserDoctor.User != nil { + data.Mobile = v.UserDoctor.User.Mobile + } + } + + if v.CreatedAt != (model.LocalTime{}) { + data.CreatedAt = time.Time(v.CreatedAt).Format("2006-01-02 15:04:05") + } + + dataSlice = append(dataSlice, data) + } + + file, err := utils.Export(header, dataSlice) + if err != nil { + return "", err + } + + // 设置文件名字 + now := time.Now() + dateTimeString := now.Format("20060102150405") // 当前时间字符串 + rand.New(rand.NewSource(time.Now().UnixNano())) // 设置随机数 + ossPath := "admin/export/药房关联医生" + dateTimeString + fmt.Sprintf("%d", rand.Intn(9000)+1000) + ".xlsx" + + // 上传oss + _, err = aliyun.PutObjectByte(ossPath, file.Bytes()) + if err != nil { + return "", err + } + + ossPath = utils.AddOssDomain("/" + ossPath) + return ossPath, nil +} diff --git a/api/service/pharmacy.go b/api/service/pharmacy.go index c7290b7..21a9334 100644 --- a/api/service/pharmacy.go +++ b/api/service/pharmacy.go @@ -109,6 +109,18 @@ func (r *PharmacyService) PutPharmacy(pharmacyId int64, req requests.PutPharmacy } } + // 若修改为禁用,校验是否有医生设为默认药房 + if req.Status != nil && *req.Status == 0 && pharmacy.Status == 1 { + doctorPharmacyDao := dao.DoctorPharmacyDao{} + totalCount, defaultCount, err := doctorPharmacyDao.GetDoctorPharmacyCountsByPharmacyId(pharmacyId) + if err != nil { + return false, errors.New("查询药房关联医生失败") + } + if defaultCount > 0 { + return false, fmt.Errorf("该药房已被 %d 位医生设为默认药房(共 %d 位医生绑定),无法禁用。请先在【药房关联医生】中调整默认药房或解除绑定后再试", defaultCount, totalCount) + } + } + tx := global.Db.Begin() defer func() { if rec := recover(); rec != nil { @@ -201,6 +213,18 @@ func (r *PharmacyService) PutPharmacyStatus(pharmacyId int64, req requests.PutPh return false, errors.New("药房不存在或已删除") } + // 若修改为禁用,校验是否有医生设为默认药房 + if req.Status != nil && *req.Status == 0 { + doctorPharmacyDao := dao.DoctorPharmacyDao{} + totalCount, defaultCount, err := doctorPharmacyDao.GetDoctorPharmacyCountsByPharmacyId(pharmacyId) + if err != nil { + return false, errors.New("查询药房关联医生失败") + } + if defaultCount > 0 { + return false, fmt.Errorf("该药房已被 %d 位医生设为默认药房(共 %d 位医生绑定),无法禁用。请先在【药房关联医生】中调整默认药房或解除绑定后再试", defaultCount, totalCount) + } + } + data := map[string]interface{}{ "status": *req.Status, } @@ -230,6 +254,19 @@ func (r *PharmacyService) DeletePharmacy(pharmacyId int64) (bool, error) { return false, errors.New("药房不存在或已删除") } + // 删除药房前校验:若有关联医生(特别是默认药房),拦截禁止删除 + doctorPharmacyDao := dao.DoctorPharmacyDao{} + totalCount, defaultCount, err := doctorPharmacyDao.GetDoctorPharmacyCountsByPharmacyId(pharmacyId) + if err != nil { + return false, errors.New("查询药房关联医生失败") + } + if defaultCount > 0 { + return false, fmt.Errorf("该药房已被 %d 位医生设为默认药房(共 %d 位医生绑定),无法删除。请先在【药房关联医生】中调整默认药房或解除绑定后再试", defaultCount, totalCount) + } + if totalCount > 0 { + return false, fmt.Errorf("该药房仍有 %d 位医生绑定,无法删除。请先在【药房关联医生】中解除绑定后再试", totalCount) + } + tx := global.Db.Begin() defer func() { if rec := recover(); rec != nil {