2025-08-04 17:18:52 +08:00

677 lines
26 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.example.caseData.service;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.caseData.config.EnvConfig;
import com.example.caseData.dao.*;
import com.example.caseData.dto.publicDto.LoginDto;
import com.example.caseData.exception.BusinessException;
import com.example.caseData.extend.aliyun.Oss;
import com.example.caseData.extend.app.Hospital.GetHospitalByUuidResponse;
import com.example.caseData.extend.app.Hospital.Hospital;
import com.example.caseData.extend.app.Score.Score;
import com.example.caseData.extend.app.UserInfo.GetUserInfoResponse;
import com.example.caseData.extend.app.UserInfo.UserInfo;
import com.example.caseData.extend.weChat.WxMaServiceUtils;
import com.example.caseData.model.*;
import com.example.caseData.utils.JwtUtil;
import com.example.caseData.utils.Replace;
import com.example.caseData.utils.Sha256Util;
import com.example.caseData.utils.StringToInt;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.time.LocalDateTime;
import java.time.Year;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.time.LocalDate;
import java.util.Random;
import static com.baomidou.mybatisplus.extension.toolkit.Db.save;
@Slf4j
@Service
public class UserService {
@Resource
private UserDao userDao;
@Resource
private UserInfo userInfo;
@Resource
private BasicHospitalDao basicHospitalDao;
@Resource
private CaseClinicalDoctorDao caseClinicalDoctorDao;
@Resource
private CaseClinicalDoctorCertDao caseClinicalDoctorCertDao;
@Resource
private CaseClinicalArticleDao caseClinicalArticleDao;
@Resource
private CaseClinicalVideoDao caseClinicalVideoDao;
@Resource
private CaseClinicalRecordScoreDao caseClinicalRecordScoreDao;
@Resource
private Hospital hospital;
@Resource
private JwtUtil jwtUtil;
@Resource
private Score score;
@Resource
private EnvConfig envConfig;
@Resource
private WxMaServiceUtils wxMaServiceUtils;
@Resource
private CertService certService;
@Resource
private StatsCaseClinicalDao statsCaseClinicalDao;
/**
* 用户登陆-手机号
* @return UserModel
*/
@Transactional
public LoginDto UserLoginWithMobile(String phone) throws BusinessException {
// 获取app用户数据
GetUserInfoResponse result = userInfo.getUserInfoByMobile(phone);
UserModel user = GetAppUserInfo(result);
// 生成jwt
String token = jwtUtil.createToken(String.valueOf(user.getUserId()));
// 获取对应医生数据
LambdaQueryWrapper<CaseClinicalDoctorModel> caseClinicalDoctorWrapper = new LambdaQueryWrapper<>();
caseClinicalDoctorWrapper.eq(CaseClinicalDoctorModel::getDoctorIden, user.getUserIden());
CaseClinicalDoctorModel caseClinicalDoctor = caseClinicalDoctorDao.selectOne(caseClinicalDoctorWrapper);
// 处理返回值
LoginDto g = new LoginDto();
g.setUserId(String.valueOf(user.getUserId()));
g.setUserName(user.getUserName());
g.setAvatar(Replace.addOssDomain(user.getAvatar()));
g.setToken(token);
if (caseClinicalDoctor != null) {
g.setDoctorId(String.valueOf(caseClinicalDoctor.getDoctorId()));
}
return g;
}
/**
* 用户登陆-app
* @param appToken 1
*/
@Transactional
public LoginDto UserLoginWithApp(String appToken) throws BusinessException {
GetUserInfoResponse result = userInfo.getUserInfoByToken(appToken);
UserModel user = GetAppUserInfo(result);
// 生成jwt
String token = jwtUtil.createToken(String.valueOf(user.getUserId()));
// 获取对应医生数据
LambdaQueryWrapper<CaseClinicalDoctorModel> caseClinicalDoctorWrapper = new LambdaQueryWrapper<>();
caseClinicalDoctorWrapper.eq(CaseClinicalDoctorModel::getDoctorIden, user.getUserIden());
CaseClinicalDoctorModel caseClinicalDoctor = caseClinicalDoctorDao.selectOne(caseClinicalDoctorWrapper);
// 处理返回值
LoginDto g = new LoginDto();
g.setUserId(String.valueOf(user.getUserId()));
g.setUserName(user.getUserName());
g.setAvatar(Replace.addOssDomain(user.getAvatar()));
g.setToken(token);
if (caseClinicalDoctor != null) {
g.setDoctorId(String.valueOf(caseClinicalDoctor.getDoctorId()));
}
return g;
}
/**
* 获取app用户数据
* @return UserModel
*/
public UserModel GetAppUserInfo(GetUserInfoResponse r) throws BusinessException {
GetUserInfoResponse.ResponsData data = r.getData();
// 查询数据库用户信息
LambdaQueryWrapper<UserModel> userModelWrapper = new LambdaQueryWrapper<>();
userModelWrapper.eq(UserModel::getUserIden, r.getData().getUuid());
UserModel user = userDao.selectOne(userModelWrapper);
if (user == null){
// 构造 UserModel 对象
user = new UserModel();
user.setUserIden(data.getUuid());
user.setUserName(data.getRealname());
user.setUserMobile(data.getMobile());
user.setMobileEncryption(SecureUtil.md5(data.getMobile()));
user.setStatus(1);
user.setRegisterSource(2);
user.setOpenId("");
user.setUnionId("");
user.setSex(0);
if (data.getPhoto() != null) {
String ossPath = handleUserImage(data.getImg_host() + data.getPhoto());
user.setAvatar(ossPath);
}else{
user.setAvatar("");
}
user.setDepartmentName(data.getOfficeName());
user.setTitle(StringToInt.DoctorTitleToInt(data.getPositionName()));
user.setAddress(data.getProvName());
int res = userDao.insert(user);
if (res <= 0){
throw new BusinessException("操作失败");
}
}else{
if (!Objects.equals(user.getUserName(), data.getRealname())){
user.setUserName(data.getRealname());
}
if (!Objects.equals(user.getUserMobile(), data.getMobile())){
user.setUserMobile(data.getMobile());
user.setMobileEncryption(SecureUtil.md5(data.getMobile()));
}
if (!Objects.equals(user.getTitle(), StringToInt.DoctorTitleToInt(data.getPositionName()))){
user.setTitle(StringToInt.DoctorTitleToInt(data.getPositionName()));
}
if (!Objects.equals(user.getDepartmentName(), data.getOfficeName())){
user.setDepartmentName(data.getOfficeName());
}
if (!Objects.equals(user.getAddress(), data.getProvName())){
user.setAddress(data.getProvName());
}
if (data.getPhoto() != null) {
try {
String ossPath = handleUserImage(data.getImg_host() + data.getPhoto());
user.setAvatar(ossPath);
}catch (Exception e){
// 不处理
}
}
userDao.updateById(user);
}
// 获取app医院数据
BasicHospitalModel basicHospital = GetAppHospital(data.getHospitalUuid());
// 修改用户所属医院
if (!Objects.equals(user.getHospitalId(), basicHospital.getHospitalId())){
user.setHospitalId(basicHospital.getHospitalId());
userDao.updateById(user);
}
// 获取对应医生数据
LambdaQueryWrapper<CaseClinicalDoctorModel> caseClinicalDoctorWrapper = new LambdaQueryWrapper<>();
caseClinicalDoctorWrapper.eq(CaseClinicalDoctorModel::getDoctorIden, user.getUserIden());
CaseClinicalDoctorModel caseClinicalDoctor = caseClinicalDoctorDao.selectOne(caseClinicalDoctorWrapper);
if (caseClinicalDoctor == null){
// 二次匹配:通过姓名-医院获取医生信息
caseClinicalDoctorWrapper = new LambdaQueryWrapper<>();
caseClinicalDoctorWrapper.eq(CaseClinicalDoctorModel::getDoctorName, user.getUserName());
caseClinicalDoctorWrapper.eq(CaseClinicalDoctorModel::getHospitalId, basicHospital.getHospitalId());
caseClinicalDoctor = caseClinicalDoctorDao.selectOne(caseClinicalDoctorWrapper);
}
if (caseClinicalDoctor == null){
CaseClinicalDoctorModel c = new CaseClinicalDoctorModel();
c.setDoctorName(user.getUserName());
c.setDoctorIden(user.getUserIden());
c.setHospitalId(user.getHospitalId());
c.setAvatar(user.getAvatar());
int res = caseClinicalDoctorDao.insert(c);
if (res <= 0){
throw new BusinessException("操作失败");
}
}else{
if (!Objects.equals(caseClinicalDoctor.getDoctorName(), data.getRealname())){
caseClinicalDoctor.setDoctorName(data.getRealname());
}
if (!Objects.equals(basicHospital.getHospitalId(), caseClinicalDoctor.getHospitalId())){
caseClinicalDoctor.setHospitalId(basicHospital.getHospitalId());
}
if (!Objects.equals(user.getAvatar(), caseClinicalDoctor.getAvatar())){
caseClinicalDoctor.setAvatar(user.getAvatar());
}
if (!Objects.equals(user.getUserIden(), caseClinicalDoctor.getDoctorIden())){
caseClinicalDoctor.setDoctorIden(user.getUserIden());
}
caseClinicalDoctorDao.updateById(caseClinicalDoctor);
}
return user;
}
/**
* 获取app医院数据
* @param hospitalIden app医院唯一标识
* @return BasicHospitalModel
*/
public BasicHospitalModel GetAppHospital(String hospitalIden) throws BusinessException {
// 查询数据库医院信息
LambdaQueryWrapper<BasicHospitalModel> basicHospitalWrapper = new LambdaQueryWrapper<>();
basicHospitalWrapper.eq(BasicHospitalModel::getHospitalIden, hospitalIden);
BasicHospitalModel basicHospital = basicHospitalDao.selectOne(basicHospitalWrapper);
if (basicHospital == null){
// 请求接口获取数据
GetHospitalByUuidResponse result = hospital.getHospitalByUuid(hospitalIden);
GetHospitalByUuidResponse.GetHospitalByUuidData data = result.getData();
// 构造 UserModel 对象
basicHospital = new BasicHospitalModel();
basicHospital.setHospitalIden(hospitalIden);
basicHospital.setHospitalName(data.getName());
basicHospital.setSource(2);
basicHospital.setHospitalLevel(data.getLevel());
basicHospital.setDoctorNumber(data.getExpert_num());
basicHospital.setProvince(data.getProv_name());
basicHospital.setCity(data.getCity_name());
save(basicHospital);
}
return basicHospital;
}
/**
* 获取app医生数据
* @return UserModel
*/
public CaseClinicalDoctorModel GetAppCaseClinicalDoctor(GetUserInfoResponse r) throws BusinessException {
GetUserInfoResponse.ResponsData data = r.getData();
// 获取app医院数据
BasicHospitalModel basicHospital = GetAppHospital(data.getHospitalUuid());
// 获取对应医生数据
LambdaQueryWrapper<CaseClinicalDoctorModel> caseClinicalDoctorWrapper = new LambdaQueryWrapper<>();
caseClinicalDoctorWrapper.eq(CaseClinicalDoctorModel::getDoctorIden, data.getUuid());
CaseClinicalDoctorModel caseClinicalDoctor = caseClinicalDoctorDao.selectOne(caseClinicalDoctorWrapper);
if (caseClinicalDoctor == null){
// 二次匹配:通过姓名-医院获取医生信息
caseClinicalDoctorWrapper = new LambdaQueryWrapper<>();
caseClinicalDoctorWrapper.eq(CaseClinicalDoctorModel::getDoctorName, data.getRealname());
caseClinicalDoctorWrapper.eq(CaseClinicalDoctorModel::getHospitalId, basicHospital.getHospitalId());
caseClinicalDoctor = caseClinicalDoctorDao.selectOne(caseClinicalDoctorWrapper);
}
if (caseClinicalDoctor == null){
caseClinicalDoctor = new CaseClinicalDoctorModel();
caseClinicalDoctor.setDoctorName(data.getRealname());
caseClinicalDoctor.setDoctorIden(data.getUuid());
caseClinicalDoctor.setHospitalId(basicHospital.getHospitalId());
if (data.getPhoto() != null) {
String ossPath = handleUserImage(data.getImg_host() + data.getPhoto());
caseClinicalDoctor.setAvatar(ossPath);
}else{
caseClinicalDoctor.setAvatar("");
}
int res = caseClinicalDoctorDao.insert(caseClinicalDoctor);
if (res <= 0){
throw new BusinessException("操作失败");
}
}else{
if (!Objects.equals(caseClinicalDoctor.getDoctorName(), data.getRealname())){
caseClinicalDoctor.setDoctorName(data.getRealname());
}
if (!Objects.equals(basicHospital.getHospitalId(), caseClinicalDoctor.getHospitalId())){
caseClinicalDoctor.setHospitalId(basicHospital.getHospitalId());
}
if (!Objects.equals(data.getUuid(), caseClinicalDoctor.getDoctorIden())){
caseClinicalDoctor.setDoctorIden(data.getUuid());
}
if (data.getPhoto() != null) {
try {
String ossPath = handleUserImage(data.getImg_host() + data.getPhoto());
caseClinicalDoctor.setAvatar(ossPath);
}catch (Exception e){
// 不处理
}
}
caseClinicalDoctorDao.updateById(caseClinicalDoctor);
}
return caseClinicalDoctor;
}
public Map getAppUser(String mobile) {
try {
HashMap<String, Object> params = new HashMap<>();
params.put("mobile", mobile);
params.put("platform", "case");
params.put("timestamp", System.currentTimeMillis() / 1000);
String signature = Sha256Util.getSign(params, "zd8V2LYD4achjFZrbHgD2PuzKuthDCVx");
params.put("signature", signature);
String result = HttpUtil.post("https://wx.igandan.com/hcp/getInfo", params);
log.info("11111");
log.info(result);
log.info("2222");
// 解析JSON
ObjectMapper objectMapper = new ObjectMapper();
Map resultMap = objectMapper.readValue(result, Map.class);
return resultMap;
} catch (Exception e) {
throw new BusinessException(e.getMessage());
}
}
/**
* 发放积分
* @param type 类型1:文章 2:视频 3:病例交流)
* @throws BusinessException
*/
public boolean ReportUserScore(String id,Integer type,String userId,Integer point) throws BusinessException{
// 获取积分发放记录
// 获取今天的日期,并设置时间为 00:00:00
LocalDateTime startOfToday = LocalDate.now().atStartOfDay(); // 例如2025-07-30 00:00:00
QueryWrapper<CaseClinicalRecordScoreModel> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("user_id", userId)
.ge("created_at", startOfToday) // created_at >= 今天 00:00:00
.orderByDesc("created_at"); // 最新的在前
List<CaseClinicalRecordScoreModel> caseClinicalRecordScores = caseClinicalRecordScoreDao.selectList(queryWrapper);
if (caseClinicalRecordScores.size() >= 3){
return true;
}
// 获取用户数据
UserModel user = userDao.selectById(userId);
if (user == null){
throw new BusinessException("操作失败");
}
// 发放积分
score.ReportUserScore(user.getUserIden(),5,"病例库-病例互动");
// 添加打赏记录
CaseClinicalRecordScoreModel data = new CaseClinicalRecordScoreModel();
data.setUserId(Long.valueOf(userId));
data.setScore(point);
data.setId(Long.valueOf(id));
data.setUserName(user.getUserName());
data.setNodeName("病例库-病例互动");
data.setType(type);
data.setScoreType(5);
caseClinicalRecordScoreDao.insert(data);
return true;
}
// 获取发放积分次数
public Integer GetReportUserScore(String userId) throws BusinessException{
// 获取积分发放记录
// 获取今天的日期,并设置时间为 00:00:00
LocalDateTime startOfToday = LocalDate.now().atStartOfDay(); // 例如2025-07-30 00:00:00
QueryWrapper<CaseClinicalRecordScoreModel> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("user_id", userId)
.ge("created_at", startOfToday) // created_at >= 今天 00:00:00
.orderByDesc("created_at"); // 最新的在前
List<CaseClinicalRecordScoreModel> caseClinicalRecordScores = caseClinicalRecordScoreDao.selectList(queryWrapper);
return caseClinicalRecordScores.size();
}
/**
* 处理用户头像:下载远程头像并上传至 OSS
*
* @param wxAvatarUrl 微信头像地址
* @return OSS 路径(以 / 开头),如 /user/avatar/202507301530123456.png
*/
public String handleUserImage(String wxAvatarUrl) {
if (wxAvatarUrl == null || wxAvatarUrl.isEmpty()) {
return null;
}
HttpURLConnection conn = null;
try {
// 1. 下载远程图片
URL url = new URL(wxAvatarUrl);
conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setReadTimeout(10000);
conn.setRequestMethod("GET");
if (conn.getResponseCode() != 200) {
throw new BusinessException("图片处理失败");
}
try (InputStream input = conn.getInputStream();
ByteArrayOutputStream output = new ByteArrayOutputStream()) {
byte[] buffer = new byte[4096];
int len;
while ((len = input.read(buffer)) != -1) {
output.write(buffer, 0, len);
}
byte[] imageBytes = output.toByteArray();
if (imageBytes.length == 0) {
throw new BusinessException("图片处理失败");
}
// 2. 生成 OSS 路径
String dateTimeStr = LocalDateTime.now()
.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
int randomSuffix = new Random().nextInt(9000) + 1000;
String ossPath = "";
if (Objects.equals(envConfig.getActive(), "dev")){
ossPath = "dev/static/images/" + dateTimeStr + randomSuffix + ".png";
}else{
ossPath = "prod/static/images/" + dateTimeStr + randomSuffix + ".png";
}
// 3. 上传 OSS
boolean success = Oss.putObject(ossPath, imageBytes);
if (!success) {
throw new BusinessException("图片处理失败");
}
return "/" + ossPath;
}
} catch (Exception e) {
// 头像处理失败
System.out.println(e.getMessage());
return "";
} finally {
if (conn != null) {
conn.disconnect();
}
}
}
/**
* 生成用户分享二维码-文章/视频
* @param id 文章/视频id
* @param type 类型 1:文章 2:视频
*/
@Transactional
public byte[] CreateUserCaseClinicalUnlimitedQrcode(String id,Integer type) throws BusinessException{
String scene = "";
String page = "pages/detail/detail";
if (type == 1){
scene = "?id=" + id + "&type=1";
}else if (type == 2){
scene = "?id=" + id + "&type=2";
}else{
throw new BusinessException("生成二维码类型错误");
}
try {
// 生成二维码
byte[] fileByte = wxMaServiceUtils.getUnlimitedQrcode(scene,page);
// 上传oss
String fileName = "";
String no = "";
if (type == 1){
no = "a" + id;
}else {
no = "v" + id;
}
if (Objects.equals(envConfig.getActive(), "dev")){
fileName = "dev/static/images/" + no + ".png";
}else{
fileName = "prod/static/images/" + no + ".png";
}
boolean res = Oss.putObject(fileName, fileByte);
if (!res) {
throw new BusinessException("生成失败");
}
if (type == 1){
// 修改文章证书
CaseClinicalArticleModel caseClinicalArticle = caseClinicalArticleDao.selectById(Long.valueOf(id));
if (caseClinicalArticle == null){
throw new BusinessException("生成失败");
}
caseClinicalArticle.setShareQrcode("/" + fileName);
caseClinicalArticleDao.updateById(caseClinicalArticle);
}else{
// 修改视频证书
CaseClinicalVideoModel caseClinicalVideo = caseClinicalVideoDao.selectById(Long.valueOf(id));
if (caseClinicalVideo == null){
throw new BusinessException("生成失败");
}
caseClinicalVideo.setShareQrcode("/" + fileName);
caseClinicalVideoDao.updateById(caseClinicalVideo);
}
return fileByte;
} catch (Exception e) {
throw new BusinessException(e.getMessage());
}
}
/**
* 生成用户证书-文章/视频
* @param id 文章/视频id
* @param type 类型 1:文章 2:视频
*/
@Transactional
public boolean CreateUserCert(String id,Integer type,String doctorId, byte[] qrCodeByte, byte[] avatarByte) throws BusinessException{
try {
String title = ""; // 标题
if (type == 1){
// 获取文章数据
CaseClinicalArticleModel caseClinicalArticle = caseClinicalArticleDao.selectById(Long.valueOf(id));
if (caseClinicalArticle == null){
throw new BusinessException("生成证书错误");
}
title = caseClinicalArticle.getArticleTitle();
}else if (type == 2){
CaseClinicalVideoModel caseClinicalVideo = caseClinicalVideoDao.selectById(Long.valueOf(id));
if (caseClinicalVideo == null){
throw new BusinessException("生成证书错误");
}
title = caseClinicalVideo.getVideoTitle();
}else{
throw new BusinessException("生成证书错误");
}
// 获取医生数据
CaseClinicalDoctorModel caseClinicalDoctor = caseClinicalDoctorDao.selectById(doctorId);
if (caseClinicalDoctor == null){
throw new BusinessException("生成证书错误");
}
// 获取证书文件
LambdaQueryWrapper<CaseClinicalDoctorCertModel> certWrapper = new LambdaQueryWrapper<>();
certWrapper.eq(CaseClinicalDoctorCertModel::getDoctorId, doctorId);
certWrapper.eq(CaseClinicalDoctorCertModel::getId, id);
certWrapper.eq(CaseClinicalDoctorCertModel::getType, type);
CaseClinicalDoctorCertModel caseClinicalDoctorCert = caseClinicalDoctorCertDao.selectOne(certWrapper);
if (caseClinicalDoctorCert != null){
return true;
}
// 获取统计数据
StatsCaseClinicalModel statsCaseClinical = statsCaseClinicalDao.selectById(1);
if (statsCaseClinical == null){
throw new BusinessException("生成证书错误");
}
// 生成证书
String certificateNo = "证书编号:GDXZALK"
+ String.valueOf(Year.now().getValue())
+ String.format("%06d", (statsCaseClinical.getArticleNum() + statsCaseClinical.getVideoNum()));
String ossPath = certService.createCert(
avatarByte,
"static/cert/seal.png",
certificateNo,
caseClinicalDoctor.getDoctorName(),
"您的案例《" + title + "》经评议,被肝胆相照临床病例库收录,特发此证。",
qrCodeByte,
doctorId
);
// 新增证书文件
caseClinicalDoctorCert = new CaseClinicalDoctorCertModel();
caseClinicalDoctorCert.setDoctorId(Long.valueOf(doctorId));
caseClinicalDoctorCert.setId(Long.valueOf(id));
caseClinicalDoctorCert.setType(type);
caseClinicalDoctorCert.setCertImage(ossPath);
caseClinicalDoctorCertDao.insert(caseClinicalDoctorCert);
return true;
} catch (Exception e) {
throw new BusinessException(e.getMessage());
}
}
}