update:医保对账
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
package com.saye.hospitalgd.controller;
|
||||
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.saye.hospitalgd.commons.date.DateDUtil;
|
||||
import com.saye.hospitalgd.commons.log.LogUtil;
|
||||
import com.saye.hospitalgd.scheduler.jobMethod.MedicalInsuranceReconciliationMethod;
|
||||
import com.saye.hospitalgd.service.MedicalInsuranceReconciliationService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author thuang
|
||||
* @version 1.0
|
||||
* @description: 医保对账Controller
|
||||
* @date 2025/10/24
|
||||
*/
|
||||
@Api(value = "医保对账相关接口")
|
||||
@Controller
|
||||
@RequestMapping("/medicalInsuranceReconciliation")
|
||||
public class MedicalInsuranceReconciliationController {
|
||||
|
||||
@Autowired
|
||||
private MedicalInsuranceReconciliationService medicalInsuranceReconciliationService;
|
||||
|
||||
/**
|
||||
* 跳转到医保对账页面
|
||||
*/
|
||||
@RequestMapping("/toMedicalInsuranceReconciliation")
|
||||
public String toMedicalInsuranceReconciliation(ModelMap modelMap) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(new Date());
|
||||
calendar.add(Calendar.DATE, -1);
|
||||
Date startDate = calendar.getTime();
|
||||
|
||||
String startTime = DateDUtil.DateToStr(DateDUtil.yyyy_MM_dd, startDate);
|
||||
String endTime = DateDUtil.getCurrentDate(DateDUtil.yyyy_MM_dd);
|
||||
|
||||
modelMap.addAttribute("startTime", startTime);
|
||||
modelMap.addAttribute("endTime", endTime);
|
||||
|
||||
return "financialReconciliation/medicalInsuranceReconciliation";
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转到医保对账结果页面
|
||||
*/
|
||||
@RequestMapping("/toMedicalInsuranceReconciliationResult")
|
||||
public String toMedicalInsuranceReconciliationResult(ModelMap modelMap) {
|
||||
return "financialReconciliation/medicalInsuranceReconciliationResult";
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行医保对账
|
||||
*/
|
||||
@ApiOperation(value = "执行医保对账", notes = "")
|
||||
@PostMapping("/executeMedicalInsuranceReconciliation")
|
||||
@ResponseBody
|
||||
public HashMap<Object, Object> executeMedicalInsuranceReconciliation(
|
||||
@ApiParam(value = "对账日期") @RequestParam String trade_date) {
|
||||
|
||||
HashMap<Object, Object> responseMap = new HashMap<>();
|
||||
|
||||
try {
|
||||
LogUtil.info(this.getClass(), "开始执行医保对账,日期:" + trade_date);
|
||||
|
||||
MedicalInsuranceReconciliationMethod reconciliationMethod = new MedicalInsuranceReconciliationMethod();
|
||||
HashMap<Object, Object> result = reconciliationMethod.executeMedicalInsuranceReconciliation(trade_date);
|
||||
|
||||
responseMap.put("code", "0".equals(result.get("errCode")) ? 0 : 1);
|
||||
responseMap.put("msg", result.get("errMsg"));
|
||||
responseMap.put("data", result.get("reconciliationResults"));
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
LogUtil.error(this.getClass(), "医保对账失败:" + e.getMessage());
|
||||
responseMap.put("code", 1);
|
||||
responseMap.put("msg", "医保对账失败:" + e.getMessage());
|
||||
}
|
||||
|
||||
return responseMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询医保对账结果
|
||||
*/
|
||||
@ApiOperation(value = "查询医保对账结果", notes = "")
|
||||
@GetMapping("/findMedicalInsuranceReconciliationResult")
|
||||
@ResponseBody
|
||||
public HashMap<Object, Object> findMedicalInsuranceReconciliationResult(
|
||||
@ApiParam(value = "开始日期") String startDate,
|
||||
@ApiParam(value = "结束日期") String endDate,
|
||||
@ApiParam(value = "险种类型") String insutype,
|
||||
@ApiParam(value = "清算类别") String clrType,
|
||||
@ApiParam(value = "对账结果") String stmtRslt,
|
||||
@ApiParam(value = "页码") int page,
|
||||
@ApiParam(value = "每页数量") int limit) {
|
||||
|
||||
HashMap<Object, Object> responseMap = new HashMap<>();
|
||||
|
||||
try {
|
||||
HashMap<Object, Object> queryMap = new HashMap<>();
|
||||
if (startDate != null && !"".equals(startDate)) {
|
||||
queryMap.put("startDate", startDate);
|
||||
}
|
||||
if (endDate != null && !"".equals(endDate)) {
|
||||
queryMap.put("endDate", endDate);
|
||||
}
|
||||
if (insutype != null && !"".equals(insutype)) {
|
||||
queryMap.put("insutype", insutype);
|
||||
}
|
||||
if (clrType != null && !"".equals(clrType)) {
|
||||
queryMap.put("clr_type", clrType);
|
||||
}
|
||||
if (stmtRslt != null && !"".equals(stmtRslt)) {
|
||||
queryMap.put("stmt_rslt", stmtRslt);
|
||||
}
|
||||
|
||||
PageHelper.startPage(page, limit);
|
||||
PageInfo<HashMap<Object, Object>> pageInfo = new PageInfo<>(
|
||||
medicalInsuranceReconciliationService.findMedicalInsuranceReconciliationResult(queryMap)
|
||||
);
|
||||
|
||||
responseMap.put("code", 0);
|
||||
responseMap.put("msg", "OK");
|
||||
responseMap.put("count", pageInfo.getTotal());
|
||||
responseMap.put("data", pageInfo.getList());
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
LogUtil.error(this.getClass(), "查询医保对账结果失败:" + e.getMessage());
|
||||
responseMap.put("code", 1);
|
||||
responseMap.put("msg", "查询失败:" + e.getMessage());
|
||||
}
|
||||
|
||||
return responseMap;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -141,14 +141,8 @@ public class MilitaryInsuranceController {
|
||||
map.put("endTime", endTime.substring(0, 10)); // 提取日期部分
|
||||
}
|
||||
|
||||
// 添加调试信息
|
||||
System.out.println("军保统计查询参数: " + map.toString());
|
||||
|
||||
List<HashMap<Object, Object>> hisDetailCount = hisDetailService.findHisDetailCountData(map);
|
||||
|
||||
// 添加调试信息
|
||||
System.out.println("军保统计查询结果: " + (hisDetailCount != null ? hisDetailCount.toString() : "null"));
|
||||
|
||||
if (hisDetailCount != null && hisDetailCount.size() > 0) {
|
||||
responseMap.put("money", hisDetailCount.get(0).get("MONEY"));
|
||||
responseMap.put("num", hisDetailCount.get(0).get("NUM"));
|
||||
@@ -236,8 +230,8 @@ public class MilitaryInsuranceController {
|
||||
|
||||
if (list.size() > 0) {
|
||||
// 定义标题头和文件名
|
||||
String[] DISTANCE_HEADERNAME = {"交易状态", "业务类型", "支付方式", "交易时间", "交易日期", "操作员", "总金额", "平台交易号", "his订单号", "HIS交易ID", "患者id", "患者姓名", "来源"};
|
||||
String[] sqlKey = {"TRADINGSTATUS", "BIZTYPE", "PAYTYPE", "TRADETIME", "TRADE_DATE", "HISOPERCODE", "AMOUNT", "PLATFORMTRANSID", "HISTRANSID", "HISTRANSID", "PATIENTID", "PATIENTNAME", "SOURCE"};
|
||||
String[] DISTANCE_HEADERNAME = {"交易状态", "业务类型", "支付方式", "交易时间", "交易日期", "操作员", "总金额", "平台交易号", "his订单号", "HIS交易ID", "患者id", "患者姓名", "来源", "清算类别", "险种类型"};
|
||||
String[] sqlKey = {"TRADINGSTATUS", "BIZTYPE", "PAYTYPE", "TRADETIME", "TRADE_DATE", "HISOPERCODE", "AMOUNT", "PLATFORMTRANSID", "HISTRANSID", "HISTRANSID", "PATIENTID", "PATIENTNAME", "SOURCE", "CLR_TYPE", "INSUTYPE"};
|
||||
|
||||
List<Object> rulList = new ArrayList<Object>(list);
|
||||
|
||||
@@ -263,6 +257,9 @@ public class MilitaryInsuranceController {
|
||||
exportXLS.modifyWidthOfHeader("5000", 9);
|
||||
exportXLS.modifyWidthOfHeader("5000", 10);
|
||||
exportXLS.modifyWidthOfHeader("10000", 11);
|
||||
exportXLS.modifyWidthOfHeader("5000", 12); // 来源
|
||||
exportXLS.modifyWidthOfHeader("5000", 13); // 清算类别
|
||||
exportXLS.modifyWidthOfHeader("5000", 14); // 险种类型
|
||||
|
||||
// 文件名称
|
||||
// 产生4位长度的随机码(由字母和数字组成)
|
||||
|
||||
@@ -144,6 +144,10 @@ public class PaymentStatisticsController {
|
||||
LinkedHashMap<String, String> zffsMap = numMap.get(str_zffs);
|
||||
if (zffsMap != null) {
|
||||
String countNum = zffsMap.get(c_jyrq);
|
||||
// 安全处理countNum,如果为null或空字符串则默认为"0"
|
||||
if (countNum == null || countNum.isEmpty()) {
|
||||
countNum = "0";
|
||||
}
|
||||
countNum = new BigDecimal(countNum).add(new BigDecimal(num1)).toString();
|
||||
zffsMap.put(c_jyrq, countNum);
|
||||
}
|
||||
@@ -181,6 +185,10 @@ public class PaymentStatisticsController {
|
||||
LinkedHashMap<String, String> zffsMap = moneyMap.get(str_zffs);
|
||||
if (zffsMap != null) {
|
||||
String countNum = zffsMap.get(c_jyrq);
|
||||
// 安全处理countNum,如果为null或空字符串则默认为"0"
|
||||
if (countNum == null || countNum.isEmpty()) {
|
||||
countNum = "0";
|
||||
}
|
||||
countNum = new BigDecimal(countNum).add(new BigDecimal(money)).toString();
|
||||
zffsMap.put(c_jyrq, countNum);
|
||||
}
|
||||
@@ -317,31 +325,85 @@ public class PaymentStatisticsController {
|
||||
String amount = StringDUtil.changeNullToEmpty(hashMap.get("AMOUNT")).trim();
|
||||
String paytype = StringDUtil.changeNullToEmpty(hashMap.get("PAYTYPE")).trim();
|
||||
|
||||
// 数据核准:确保PayType在预定义范围内
|
||||
if (!hisMoneyData.containsKey(paytype)) {
|
||||
log.warn("发现未预定义的PayType: [{}], 数据: {}, 已归类为其他支付方式", paytype, hashMap);
|
||||
paytype = "4"; // 归类为其他支付方式
|
||||
}
|
||||
|
||||
// 数据核准:确保I_JYQD在预定义范围内
|
||||
if (!thirdMoneyData.containsKey(i_zffs)) {
|
||||
log.warn("发现未预定义的I_JYQD: [{}], 数据: {}, 已归类为其他支付方式", i_zffs, hashMap);
|
||||
i_zffs = "5"; // 归类为其他支付方式
|
||||
}
|
||||
|
||||
// 如果银行端金额不为空
|
||||
|
||||
if (StrUtil.isNotBlank(i_jyje)) {
|
||||
log.info("hashMap is :" + hashMap);
|
||||
log.info("aaa is : " + thirdMoneyData.get(i_zffs));
|
||||
BigDecimal money = Convert.toBigDecimal(thirdMoneyData.get(i_zffs));
|
||||
money = money.add(new BigDecimal(i_jyje));
|
||||
thirdMoneyData.put(i_zffs, money.toString());
|
||||
try {
|
||||
log.info("处理银行端数据: i_zffs={}, i_jyje={}", i_zffs, i_jyje);
|
||||
|
||||
int num = Integer.parseInt(StringDUtil.changeNullToEmpty(thirdNumData.get(i_zffs)));
|
||||
num++;
|
||||
thirdNumData.put(i_zffs, num + "");
|
||||
// 验证金额格式
|
||||
BigDecimal transAmount = new BigDecimal(i_jyje);
|
||||
if (transAmount.compareTo(BigDecimal.ZERO) < 0) {
|
||||
log.warn("发现负数金额: i_jyje={}, 数据: {}", i_jyje, hashMap);
|
||||
}
|
||||
|
||||
// 安全获取当前金额,如果为null则默认为BigDecimal.ZERO
|
||||
BigDecimal money = Convert.toBigDecimal(thirdMoneyData.get(i_zffs), BigDecimal.ZERO);
|
||||
money = money.add(transAmount);
|
||||
thirdMoneyData.put(i_zffs, money.toString());
|
||||
|
||||
// 安全获取当前数量,如果为null或空字符串则默认为"0"
|
||||
String currentNumStr = StringDUtil.changeNullToEmpty(thirdNumData.get(i_zffs));
|
||||
if (currentNumStr.isEmpty()) {
|
||||
currentNumStr = "0";
|
||||
}
|
||||
|
||||
int num = Integer.parseInt(currentNumStr);
|
||||
num++;
|
||||
thirdNumData.put(i_zffs, num + "");
|
||||
|
||||
} catch (NumberFormatException e) {
|
||||
log.error("银行端金额格式错误: i_jyje=[{}], 数据: {}, 错误: {}", i_jyje, hashMap, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 如果his端金额不为空
|
||||
|
||||
if (StrUtil.isNotBlank(amount)) {
|
||||
log.info("hashMap is :" + hashMap);
|
||||
BigDecimal money = new BigDecimal(StringDUtil.changeNullToEmpty(hisMoneyData.get(paytype)));
|
||||
money = money.add(new BigDecimal(amount));
|
||||
hisMoneyData.put(paytype, money.toString());
|
||||
try {
|
||||
log.info("处理HIS端数据: paytype={}, amount={}", paytype, amount);
|
||||
|
||||
int num = Integer.parseInt(StringDUtil.changeNullToEmpty(hisNumData.get(paytype)));
|
||||
num++;
|
||||
hisNumData.put(paytype, num + "");
|
||||
// 验证金额格式
|
||||
BigDecimal transAmount = new BigDecimal(amount);
|
||||
if (transAmount.compareTo(BigDecimal.ZERO) < 0) {
|
||||
log.warn("发现负数金额: amount={}, 数据: {}", amount, hashMap);
|
||||
}
|
||||
|
||||
// 安全获取当前金额,如果为null或空字符串则默认为"0"
|
||||
String currentMoneyStr = StringDUtil.changeNullToEmpty(hisMoneyData.get(paytype));
|
||||
if (currentMoneyStr.isEmpty()) {
|
||||
currentMoneyStr = "0";
|
||||
}
|
||||
|
||||
BigDecimal money = new BigDecimal(currentMoneyStr);
|
||||
money = money.add(transAmount);
|
||||
hisMoneyData.put(paytype, money.toString());
|
||||
|
||||
// 安全获取当前数量,如果为null或空字符串则默认为"0"
|
||||
String currentNumStr = StringDUtil.changeNullToEmpty(hisNumData.get(paytype));
|
||||
if (currentNumStr.isEmpty()) {
|
||||
currentNumStr = "0";
|
||||
}
|
||||
|
||||
int num = Integer.parseInt(currentNumStr);
|
||||
num++;
|
||||
hisNumData.put(paytype, num + "");
|
||||
|
||||
} catch (NumberFormatException e) {
|
||||
log.error("HIS端金额格式错误: amount=[{}], 数据: {}, 错误: {}", amount, hashMap, e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,17 @@ public class BaseQuartzConfigController{
|
||||
@Autowired
|
||||
private DicinfoService dicinfoService;
|
||||
|
||||
/**
|
||||
* @description 跳转到定时任务管理页面
|
||||
* @author thuang
|
||||
* @created 2025/10/24
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping("/toQuartzManage")
|
||||
public String toQuartzManage() {
|
||||
return "system/quartzManage";
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 查询所有的定时任务
|
||||
* @author thuang
|
||||
|
||||
@@ -23,4 +23,8 @@ public class HisbillsHistory {
|
||||
private String PatientName;
|
||||
private String source;
|
||||
private String trade_date;
|
||||
private String clrType; // 清算类别
|
||||
private String insutype; // 险种类型
|
||||
private String ybzhAmount; // 医保账户金额
|
||||
private String ybtcAmount; // 医保统筹金额
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.saye.hospitalgd.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author thuang
|
||||
* @version 1.0
|
||||
* @description: 医保对账结果实体类
|
||||
* @date 2025/10/24
|
||||
*/
|
||||
@Data
|
||||
public class MedicalInsuranceReconciliationResult {
|
||||
|
||||
private String id; // 主键ID
|
||||
private String tradeDate; // 对账日期
|
||||
private String insutype; // 险种类型
|
||||
private String clrType; // 清算类别
|
||||
private String medfee_sumamt; // 医疗费用总额
|
||||
private String fund_pay_sumamt; // 基金支付总额(医保统筹)
|
||||
private String acct_pay; // 账户支付金额(医保账户)
|
||||
private String fixmedins_setl_cnt; // 定点医药机构结算笔数
|
||||
private String stmt_rslt; // 对账结果(0-成功,1-失败)
|
||||
private String stmt_rslt_dscr; // 对账结果描述
|
||||
private String apiResult; // 接口调用结果
|
||||
private String createTime; // 创建时间
|
||||
private String modifyTime; // 修改时间
|
||||
}
|
||||
|
||||
|
||||
@@ -41,4 +41,6 @@ public interface HisDetailMapper {
|
||||
void deleteHisBillOriginalHYByParam(HashMap<Object, Object> deleteMap) throws Exception;
|
||||
|
||||
void insertAllHisBillOriginalHY(List<HashMap<Object, Object>> addList) throws Exception;
|
||||
|
||||
List<HashMap<Object, Object>> findMedicalInsuranceGroupData(HashMap<Object, Object> map) throws Exception;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.saye.hospitalgd.mapper;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author thuang
|
||||
* @version 1.0
|
||||
* @description: 医保对账Mapper
|
||||
* @date 2025/10/24
|
||||
*/
|
||||
@Mapper
|
||||
public interface MedicalInsuranceReconciliationMapper {
|
||||
|
||||
/**
|
||||
* 插入医保对账结果
|
||||
*/
|
||||
void insertMedicalInsuranceReconciliationResult(HashMap<Object, Object> map) throws Exception;
|
||||
|
||||
/**
|
||||
* 批量插入医保对账结果
|
||||
*/
|
||||
void insertMedicalInsuranceReconciliationResultBatch(List<HashMap<Object, Object>> list) throws Exception;
|
||||
|
||||
/**
|
||||
* 查询医保对账结果
|
||||
*/
|
||||
List<HashMap<Object, Object>> findMedicalInsuranceReconciliationResult(HashMap<Object, Object> map) throws Exception;
|
||||
|
||||
/**
|
||||
* 删除医保对账结果
|
||||
*/
|
||||
void deleteMedicalInsuranceReconciliationResult(HashMap<Object, Object> map) throws Exception;
|
||||
}
|
||||
|
||||
|
||||
@@ -72,4 +72,5 @@ public interface FinanceUserMapper {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ public class BaseQuartzConfigEntity {
|
||||
private String quartzGroup;
|
||||
private String status;
|
||||
private String quartzClass;
|
||||
private String quartzType;
|
||||
private String remark;
|
||||
private String createUserId;
|
||||
private String expression;
|
||||
@@ -41,6 +42,12 @@ public class BaseQuartzConfigEntity {
|
||||
public void setQuartzClass(String quartzClass) {
|
||||
this.quartzClass = quartzClass;
|
||||
}
|
||||
public String getQuartzType() {
|
||||
return quartzType;
|
||||
}
|
||||
public void setQuartzType(String quartzType) {
|
||||
this.quartzType = quartzType;
|
||||
}
|
||||
public String getRemark() {
|
||||
return remark;
|
||||
}
|
||||
|
||||
@@ -40,4 +40,5 @@ public class FinanceUser {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.saye.hospitalgd.scheduler.job;
|
||||
|
||||
import com.saye.hospitalgd.commons.log.LogUtil;
|
||||
import com.saye.hospitalgd.scheduler.jobMethod.MedicalInsuranceReconciliationMethod;
|
||||
import org.quartz.Job;
|
||||
import org.quartz.JobDataMap;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobExecutionException;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* @author yuan
|
||||
* @version 1.0
|
||||
* @description: 医保对账定时任务
|
||||
* @date 2025/10/24
|
||||
*/
|
||||
public class MedicalInsuranceReconciliationJob implements Job {
|
||||
|
||||
@Override
|
||||
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
|
||||
|
||||
JobDataMap jobDataMap = jobExecutionContext.getMergedJobDataMap();
|
||||
String id = jobDataMap.getString("id");
|
||||
String name = jobDataMap.getString("name");
|
||||
String trade_date = jobDataMap.getString("trade_date");
|
||||
|
||||
// 如果没有指定对账日期,使用前一天的日期(医保对账通常对前一天的数据)
|
||||
if (trade_date == null || trade_date.trim().isEmpty()) {
|
||||
java.util.Calendar calendar = java.util.Calendar.getInstance();
|
||||
calendar.add(java.util.Calendar.DATE, -1); // 前一天
|
||||
java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd");
|
||||
trade_date = sdf.format(calendar.getTime());
|
||||
LogUtil.info(this.getClass(), "未指定对账日期,自动使用前一天日期:" + trade_date);
|
||||
}
|
||||
|
||||
LogUtil.info(this.getClass(), "医保对账定时任务【" + name + "】开始执行,日期:" + trade_date);
|
||||
|
||||
try {
|
||||
MedicalInsuranceReconciliationMethod method = new MedicalInsuranceReconciliationMethod();
|
||||
HashMap<Object, Object> result = method.executeMedicalInsuranceReconciliation(trade_date);
|
||||
|
||||
String errCode = (String) result.get("errCode");
|
||||
if ("0".equals(errCode)) {
|
||||
LogUtil.info(this.getClass(), "医保对账定时任务【" + name + "】执行成功");
|
||||
} else {
|
||||
LogUtil.error(this.getClass(), "医保对账定时任务【" + name + "】执行失败:" + result.get("errMsg"));
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
LogUtil.error(this.getClass(), "医保对账定时任务【" + name + "】执行异常:" + e.getMessage());
|
||||
throw new JobExecutionException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -158,6 +158,12 @@ public class HISGetDataMethodByJH {
|
||||
String amount = StringDUtil.changeNullToEmpty(hisBillHashMap.get("amount"));
|
||||
String tradeTime = StringDUtil.changeNullToEmpty(hisBillHashMap.get("tradeTime"));
|
||||
|
||||
// 提取新增字段:清算类别、险种类型、医保账户金额、医保统筹金额
|
||||
String clrType = StringDUtil.changeNullToEmpty(hisBillHashMap.get("clrType"));
|
||||
String insutype = StringDUtil.changeNullToEmpty(hisBillHashMap.get("insutype"));
|
||||
String ybzhAmount = StringDUtil.changeNullToEmpty(hisBillHashMap.get("ybzhAmount"));
|
||||
String ybtcAmount = StringDUtil.changeNullToEmpty(hisBillHashMap.get("ybtcAmount"));
|
||||
|
||||
// 只有当缺少关键业务信息时才跳过(患者ID、金额、交易时间都为空)
|
||||
if ("".equals(patientId) && "".equals(amount) && "".equals(tradeTime)){
|
||||
log.warn("跳过缺少关键业务信息的记录: powerTranID={}, receiptNO={}, hisTransId={}",
|
||||
@@ -222,6 +228,10 @@ public class HISGetDataMethodByJH {
|
||||
addMap.put("patientName",patientName);
|
||||
addMap.put("trade_date",thistrade_date);
|
||||
addMap.put("his_wsdl_id",his_wsdl_id);
|
||||
addMap.put("clrType",clrType); // 清算类别
|
||||
addMap.put("insutype",insutype); // 险种类型
|
||||
addMap.put("ybzhAmount",ybzhAmount); // 医保账户金额
|
||||
addMap.put("ybtcAmount",ybtcAmount); // 医保统筹金额
|
||||
|
||||
//如果是现金记录先放进现金集合内
|
||||
if (cash_code.equals(payType)){
|
||||
@@ -259,6 +269,10 @@ public class HISGetDataMethodByJH {
|
||||
addMap.put("patientName","");
|
||||
addMap.put("trade_date",trade_date);
|
||||
addMap.put("his_wsdl_id",his_wsdl_id);
|
||||
addMap.put("clrType",""); // 现金记录没有清算类别
|
||||
addMap.put("insutype",""); // 现金记录没有险种类型
|
||||
addMap.put("ybzhAmount","0"); // 现金记录没有医保账户金额
|
||||
addMap.put("ybtcAmount","0"); // 现金记录没有医保统筹金额
|
||||
|
||||
cashMap.put(hisOperCode+"_"+payMethod,addMap);
|
||||
}else {
|
||||
@@ -300,6 +314,10 @@ public class HISGetDataMethodByJH {
|
||||
addMap.put("patientName","");
|
||||
addMap.put("trade_date",trade_date);
|
||||
addMap.put("his_wsdl_id",his_wsdl_id);
|
||||
addMap.put("clrType",""); // 支票记录没有清算类别
|
||||
addMap.put("insutype",""); // 支票记录没有险种类型
|
||||
addMap.put("ybzhAmount","0"); // 支票记录没有医保账户金额
|
||||
addMap.put("ybtcAmount","0"); // 支票记录没有医保统筹金额
|
||||
|
||||
zhipiaoMap.put(hisOperCode+"_"+payMethod,addMap);
|
||||
}else {
|
||||
|
||||
@@ -0,0 +1,355 @@
|
||||
package com.saye.hospitalgd.scheduler.jobMethod;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.saye.hospitalgd.commons.date.DateDUtil;
|
||||
import com.saye.hospitalgd.commons.getBean.GetBeanUtil;
|
||||
import com.saye.hospitalgd.commons.log.LogUtil;
|
||||
import com.saye.hospitalgd.commons.string.StringDUtil;
|
||||
import com.saye.hospitalgd.commons.uuid.UUIDGenerator;
|
||||
import com.saye.hospitalgd.service.HisDetailService;
|
||||
import com.saye.hospitalgd.service.MedicalInsuranceReconciliationService;
|
||||
import com.saye.hospitalgd.service.impl.HisDetailServiceImpl;
|
||||
import com.saye.hospitalgd.service.impl.MedicalInsuranceReconciliationServiceImpl;
|
||||
import com.saye.hospitalgd.service.system.DicinfoService;
|
||||
import com.saye.hospitalgd.service.system.impl.DicinfoServiceImpl;
|
||||
import com.saye.hospitalgd.util.SSLUtil;
|
||||
import com.saye.hospitalgd.util.pojo.HttpResult;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author thuang
|
||||
* @version 1.0
|
||||
* @description: 医保对账方法
|
||||
* @date 2025/10/24
|
||||
*/
|
||||
public class MedicalInsuranceReconciliationMethod {
|
||||
|
||||
// 普通医保局对账接口地址
|
||||
private static final String MEDICAL_INSURANCE_URL = "https://10.134.97.159/fsi/api/ybSettlementStmtService/stmtTotal";
|
||||
|
||||
// 工商医保对账接口地址(险种99410专用)
|
||||
private static final String GONGSHANG_INSURANCE_URL = "http://10.150.4.74:8111/gssetl/api/hisbiz";
|
||||
|
||||
// 工商医保险种代码
|
||||
private static final String GONGSHANG_INSUTYPE = "99410";
|
||||
|
||||
// 固定参数
|
||||
private static final String SETL_OPTINS = "640104";
|
||||
private static final String INFNO = "3201";
|
||||
private static final String INFVER = "1.0";
|
||||
private static final String FIXMEDINS_CODE = "H64010400022";
|
||||
private static final String FIXMEDINS_NAME = "中国人民武装警察部队宁夏回族自治区总队医院";
|
||||
private static final String INSUPLC_ADMDVS = "410000";
|
||||
private static final String MDTRTAREA_ADMVS = "411302";
|
||||
private static final String OPTER = "ADMIN";
|
||||
private static final String OPTER_NAME = "系统管理员";
|
||||
private static final String OPTER_TYPE = "1";
|
||||
private static final String RECER_SYS_CODE = "HIS";
|
||||
private static final String SIGNTYPE = "SM3";
|
||||
|
||||
/**
|
||||
* 执行医保对账
|
||||
* @param trade_date 对账日期
|
||||
* @return 对账结果
|
||||
*/
|
||||
public HashMap<Object, Object> executeMedicalInsuranceReconciliation(String trade_date) {
|
||||
HashMap<Object, Object> responseMap = new HashMap<>();
|
||||
String errCode = "0";
|
||||
String errMsg = "";
|
||||
|
||||
try {
|
||||
LogUtil.info(this.getClass(), "开始执行医保对账,日期:" + trade_date);
|
||||
|
||||
LogUtil.info(this.getClass(), "开始查询医保数据(不限制PayType)");
|
||||
|
||||
// 1. 从数据库查询医保数据,按险种和清算类别分组统计(不限制PayType)
|
||||
HisDetailService hisDetailService = GetBeanUtil.getBean(HisDetailServiceImpl.class);
|
||||
|
||||
HashMap<Object, Object> queryMap = new HashMap<>();
|
||||
queryMap.put("trade_date", trade_date);
|
||||
|
||||
// 查询所有有险种和清算类别的记录(不限制PayType)
|
||||
List<HashMap<Object, Object>> medicalRecords = hisDetailService.findMedicalInsuranceGroupData(queryMap);
|
||||
|
||||
if (medicalRecords == null || medicalRecords.size() == 0) {
|
||||
LogUtil.info(this.getClass(), "医保对账:当日没有医保数据,日期:" + trade_date);
|
||||
errMsg = "当日没有医保数据";
|
||||
responseMap.put("errCode", errCode);
|
||||
responseMap.put("errMsg", errMsg);
|
||||
responseMap.put("reconciliationResults", new ArrayList<>());
|
||||
return responseMap;
|
||||
}
|
||||
|
||||
LogUtil.info(this.getClass(), "查询到医保分组数据:" + medicalRecords.size() + " 组");
|
||||
|
||||
// 删除当天旧的对账结果
|
||||
MedicalInsuranceReconciliationService reconciliationService =
|
||||
GetBeanUtil.getBean(MedicalInsuranceReconciliationServiceImpl.class);
|
||||
HashMap<Object, Object> deleteMap = new HashMap<>();
|
||||
deleteMap.put("trade_date", trade_date);
|
||||
reconciliationService.deleteMedicalInsuranceReconciliationResult(deleteMap);
|
||||
|
||||
// 2. 遍历每个险种和清算类别的组合,调用医保局接口
|
||||
List<HashMap<Object, Object>> reconciliationResults = new ArrayList<>();
|
||||
|
||||
for (HashMap<Object, Object> record : medicalRecords) {
|
||||
String insutype = StringDUtil.changeNullToEmpty(record.get("INSUTYPE"));
|
||||
String clrType = StringDUtil.changeNullToEmpty(record.get("CLR_TYPE"));
|
||||
String medfee_sumamt = StringDUtil.changeNullToEmpty(record.get("MEDFEE_SUMAMT"));
|
||||
String fund_pay_sumamt = StringDUtil.changeNullToEmpty(record.get("FUND_PAY_SUMAMT"));
|
||||
String acct_pay = StringDUtil.changeNullToEmpty(record.get("ACCT_PAY"));
|
||||
String fixmedins_setl_cnt = StringDUtil.changeNullToEmpty(record.get("FIXMEDINS_SETL_CNT"));
|
||||
|
||||
// 跳过空的险种或清算类别
|
||||
if ("".equals(insutype) || "".equals(clrType)) {
|
||||
LogUtil.info(this.getClass(), "跳过险种或清算类别为空的记录");
|
||||
continue;
|
||||
}
|
||||
|
||||
LogUtil.info(this.getClass(), String.format("处理险种:%s,清算类别:%s,交易笔数:%s,总金额:%s",
|
||||
insutype, clrType, fixmedins_setl_cnt, medfee_sumamt));
|
||||
|
||||
try {
|
||||
// 3. 调用医保局对账接口
|
||||
HashMap<Object, Object> callResult = callMedicalInsuranceAPI(
|
||||
trade_date, insutype, clrType, medfee_sumamt,
|
||||
fund_pay_sumamt, acct_pay, fixmedins_setl_cnt
|
||||
);
|
||||
|
||||
// 4. 记录对账结果
|
||||
HashMap<Object, Object> resultMap = new HashMap<>();
|
||||
resultMap.put("id", UUIDGenerator.getUUID());
|
||||
resultMap.put("trade_date", trade_date);
|
||||
resultMap.put("insutype", insutype);
|
||||
resultMap.put("clr_type", clrType);
|
||||
resultMap.put("medfee_sumamt", medfee_sumamt);
|
||||
resultMap.put("fund_pay_sumamt", fund_pay_sumamt);
|
||||
resultMap.put("acct_pay", acct_pay);
|
||||
resultMap.put("fixmedins_setl_cnt", fixmedins_setl_cnt);
|
||||
resultMap.put("setl_optins", callResult.get("setl_optins"));
|
||||
resultMap.put("stmt_rslt", callResult.get("stmt_rslt"));
|
||||
resultMap.put("stmt_rslt_dscr", callResult.get("stmt_rslt_dscr"));
|
||||
resultMap.put("infcode", callResult.get("infcode"));
|
||||
resultMap.put("err_msg", callResult.get("err_msg"));
|
||||
resultMap.put("warn_msg", callResult.get("warn_msg"));
|
||||
resultMap.put("refmsg_time", callResult.get("refmsg_time"));
|
||||
resultMap.put("respond_time", callResult.get("respond_time"));
|
||||
resultMap.put("inf_refmsgid", callResult.get("inf_refmsgid"));
|
||||
resultMap.put("api_result", callResult.get("api_result"));
|
||||
resultMap.put("create_time", DateDUtil.getCurrentDate(DateDUtil.yyyy_MM_dd_HH_mm_ss));
|
||||
resultMap.put("modify_time", DateDUtil.getCurrentDate(DateDUtil.yyyy_MM_dd_HH_mm_ss));
|
||||
|
||||
reconciliationResults.add(resultMap);
|
||||
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(this.getClass(), String.format("医保对账失败,险种:%s,清算类别:%s,错误:%s",
|
||||
insutype, clrType, e.getMessage()));
|
||||
|
||||
// 记录失败结果
|
||||
HashMap<Object, Object> resultMap = new HashMap<>();
|
||||
resultMap.put("id", UUIDGenerator.getUUID());
|
||||
resultMap.put("trade_date", trade_date);
|
||||
resultMap.put("insutype", insutype);
|
||||
resultMap.put("clr_type", clrType);
|
||||
resultMap.put("medfee_sumamt", medfee_sumamt);
|
||||
resultMap.put("fund_pay_sumamt", fund_pay_sumamt);
|
||||
resultMap.put("acct_pay", acct_pay);
|
||||
resultMap.put("fixmedins_setl_cnt", fixmedins_setl_cnt);
|
||||
resultMap.put("stmt_rslt", "9");
|
||||
resultMap.put("stmt_rslt_dscr", "调用医保局接口失败:" + e.getMessage());
|
||||
resultMap.put("api_result", "ERROR");
|
||||
resultMap.put("create_time", DateDUtil.getCurrentDate(DateDUtil.yyyy_MM_dd_HH_mm_ss));
|
||||
resultMap.put("modify_time", DateDUtil.getCurrentDate(DateDUtil.yyyy_MM_dd_HH_mm_ss));
|
||||
|
||||
reconciliationResults.add(resultMap);
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 批量保存对账结果到数据库
|
||||
if (reconciliationResults.size() > 0) {
|
||||
reconciliationService.insertMedicalInsuranceReconciliationResultBatch(reconciliationResults);
|
||||
}
|
||||
|
||||
responseMap.put("reconciliationResults", reconciliationResults);
|
||||
LogUtil.info(this.getClass(), "医保对账完成,共处理 " + reconciliationResults.size() + " 组数据");
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
errCode = "999";
|
||||
errMsg = "医保对账失败:" + e.getMessage();
|
||||
LogUtil.error(this.getClass(), errMsg);
|
||||
}
|
||||
|
||||
responseMap.put("errCode", errCode);
|
||||
responseMap.put("errMsg", errMsg);
|
||||
return responseMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用医保局对账接口
|
||||
*/
|
||||
private HashMap<Object, Object> callMedicalInsuranceAPI(
|
||||
String trade_date, String insutype, String clr_type,
|
||||
String medfee_sumamt, String fund_pay_sumamt, String acct_pay,
|
||||
String fixmedins_setl_cnt) throws Exception {
|
||||
|
||||
HashMap<Object, Object> result = new HashMap<>();
|
||||
|
||||
// 计算日期范围(当日到当日)
|
||||
String stmt_begndate = trade_date;
|
||||
String stmt_enddate = trade_date;
|
||||
|
||||
// 生成当前时间
|
||||
String inf_time = DateDUtil.getCurrentDate(DateDUtil.yyyy_MM_dd_HH_mm_ss);
|
||||
|
||||
// 生成消息ID(机构编码+时间戳+序号)
|
||||
String msgid = FIXMEDINS_CODE + DateDUtil.DateToStr("yyyyMMddHHmmss", new Date()) + "0001";
|
||||
|
||||
// 构建请求JSON
|
||||
JSONObject requestJson = new JSONObject();
|
||||
requestJson.put("cainfo", "");
|
||||
requestJson.put("dev_no", "");
|
||||
requestJson.put("dev_safe_info", "");
|
||||
requestJson.put("fixmedins_code", FIXMEDINS_CODE);
|
||||
requestJson.put("fixmedins_name", FIXMEDINS_NAME);
|
||||
requestJson.put("inf_time", inf_time);
|
||||
requestJson.put("infno", INFNO);
|
||||
requestJson.put("infver", INFVER);
|
||||
requestJson.put("insuplc_admdvs", INSUPLC_ADMDVS);
|
||||
requestJson.put("mdtrtarea_admvs", MDTRTAREA_ADMVS);
|
||||
requestJson.put("msgid", msgid);
|
||||
requestJson.put("opter", OPTER);
|
||||
requestJson.put("opter_name", OPTER_NAME);
|
||||
requestJson.put("opter_type", OPTER_TYPE);
|
||||
requestJson.put("recer_sys_code", RECER_SYS_CODE);
|
||||
requestJson.put("sign_no", "");
|
||||
requestJson.put("signtype", SIGNTYPE);
|
||||
|
||||
// 构建input.data
|
||||
JSONObject inputData = new JSONObject();
|
||||
inputData.put("acct_pay", acct_pay);
|
||||
inputData.put("clr_type", clr_type);
|
||||
inputData.put("fixmedins_setl_cnt", fixmedins_setl_cnt);
|
||||
inputData.put("fund_pay_sumamt", fund_pay_sumamt);
|
||||
inputData.put("insutype", insutype);
|
||||
inputData.put("medfee_sumamt", medfee_sumamt);
|
||||
inputData.put("setl_optins", SETL_OPTINS);
|
||||
inputData.put("stmt_begndate", stmt_begndate);
|
||||
inputData.put("stmt_enddate", stmt_enddate);
|
||||
|
||||
JSONObject input = new JSONObject();
|
||||
input.put("data", inputData);
|
||||
requestJson.put("input", input);
|
||||
|
||||
LogUtil.info(this.getClass(), "医保对账请求(日期范围:" + stmt_begndate + " 到 " + stmt_enddate + "):" + requestJson.toJSONString());
|
||||
|
||||
// 根据险种选择接口地址
|
||||
String apiUrl;
|
||||
boolean isGongshang = GONGSHANG_INSUTYPE.equals(insutype);
|
||||
if (isGongshang) {
|
||||
apiUrl = GONGSHANG_INSURANCE_URL;
|
||||
LogUtil.info(this.getClass(), "险种99410使用工商医保接口(当日到当日):" + apiUrl);
|
||||
} else {
|
||||
apiUrl = MEDICAL_INSURANCE_URL;
|
||||
LogUtil.info(this.getClass(), "使用普通医保接口(当日到当日):" + apiUrl);
|
||||
}
|
||||
|
||||
// 发送HTTP请求(使用信任所有SSL证书的HttpClient)
|
||||
CloseableHttpClient httpClient = null;
|
||||
try {
|
||||
httpClient = SSLUtil.createSSLClientDefault();
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(this.getClass(), "创建SSL HttpClient失败:" + e.getMessage());
|
||||
// 如果创建SSL HttpClient失败,使用默认的HttpClient
|
||||
httpClient = HttpClients.createDefault();
|
||||
}
|
||||
|
||||
HttpPost httpPost = new HttpPost(apiUrl);
|
||||
httpPost.setHeader("Content-Type", "application/json;charset=UTF-8");
|
||||
httpPost.setEntity(new StringEntity(requestJson.toJSONString(), StandardCharsets.UTF_8));
|
||||
|
||||
CloseableHttpResponse response = null;
|
||||
try {
|
||||
response = httpClient.execute(httpPost);
|
||||
String responseStr = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
|
||||
|
||||
LogUtil.info(this.getClass(), "医保对账响应:" + responseStr);
|
||||
|
||||
// 解析响应
|
||||
JSONObject responseJson = JSON.parseObject(responseStr);
|
||||
|
||||
// 存储基础响应信息
|
||||
result.put("infcode", responseJson.getInteger("infcode"));
|
||||
result.put("err_msg", responseJson.getString("err_msg"));
|
||||
result.put("warn_msg", responseJson.getString("warn_msg"));
|
||||
result.put("refmsg_time", responseJson.getString("refmsg_time"));
|
||||
result.put("respond_time", responseJson.getString("respond_time"));
|
||||
result.put("inf_refmsgid", responseJson.getString("inf_refmsgid"));
|
||||
|
||||
Integer infcode = responseJson.getInteger("infcode");
|
||||
if (infcode != null && infcode == 0) {
|
||||
// 请求成功
|
||||
JSONObject output = responseJson.getJSONObject("output");
|
||||
if (output != null && output.containsKey("stmtinfo")) {
|
||||
JSONObject stmtinfo = output.getJSONObject("stmtinfo");
|
||||
result.put("setl_optins", stmtinfo.getString("setl_optins"));
|
||||
|
||||
String stmt_rslt = stmtinfo.getString("stmt_rslt");
|
||||
String stmt_rslt_dscr = stmtinfo.getString("stmt_rslt_dscr");
|
||||
|
||||
// 工商医保的对账结果处理(99410险种)
|
||||
if (isGongshang) {
|
||||
// 工商医保返回格式:
|
||||
// stmt_rslt: "101" 表示有差异(对应普通医保的"1"失败)
|
||||
// stmt_rslt: "0" 表示一致(对应普通医保的"0"成功)
|
||||
if ("101".equals(stmt_rslt)) {
|
||||
result.put("stmt_rslt", "1"); // 转换为标准的失败标识
|
||||
LogUtil.info(this.getClass(), "工商医保对账结果:有差异 - " + stmt_rslt_dscr);
|
||||
} else if ("0".equals(stmt_rslt)) {
|
||||
result.put("stmt_rslt", "0"); // 成功
|
||||
LogUtil.info(this.getClass(), "工商医保对账结果:一致");
|
||||
} else {
|
||||
result.put("stmt_rslt", stmt_rslt); // 保持原值
|
||||
LogUtil.info(this.getClass(), "工商医保对账结果:" + stmt_rslt);
|
||||
}
|
||||
} else {
|
||||
// 普通医保直接使用返回值
|
||||
result.put("stmt_rslt", stmt_rslt);
|
||||
}
|
||||
|
||||
result.put("stmt_rslt_dscr", stmt_rslt_dscr);
|
||||
result.put("api_result", "SUCCESS");
|
||||
} else {
|
||||
result.put("stmt_rslt", "9");
|
||||
result.put("stmt_rslt_dscr", "返回数据格式错误");
|
||||
result.put("api_result", "ERROR");
|
||||
}
|
||||
} else {
|
||||
// 请求失败
|
||||
String err_msg = responseJson.getString("err_msg");
|
||||
result.put("stmt_rslt", "9");
|
||||
result.put("stmt_rslt_dscr", "医保局返回错误:" + err_msg);
|
||||
result.put("api_result", "ERROR");
|
||||
}
|
||||
|
||||
} finally {
|
||||
if (response != null) {
|
||||
response.close();
|
||||
}
|
||||
httpClient.close();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,6 +80,17 @@ public class ReconciliationMethod {
|
||||
}
|
||||
searchMap.put("military_code", military_code);
|
||||
|
||||
// 查询医保支付方式的dicvalue(需要从常规对账中过滤掉)
|
||||
String medical_insurance_code = ""; // 默认为空,表示不过滤
|
||||
HashMap<String, String> medicalSearchMap = new HashMap<>();
|
||||
medicalSearchMap.put("parentCode", "PAY_TYPE");
|
||||
medicalSearchMap.put("dicname", "医保");
|
||||
List<HashMap<Object, Object>> medicalPayTypeList = dicinfoService.selectDicinfoListByCondition(medicalSearchMap);
|
||||
if (medicalPayTypeList != null && medicalPayTypeList.size() > 0) {
|
||||
medical_insurance_code = StringDUtil.changeNullToEmpty(medicalPayTypeList.get(0).get("DICVALUE"));
|
||||
}
|
||||
searchMap.put("medical_insurance_code", medical_insurance_code);
|
||||
|
||||
//查询his和三方记录
|
||||
List<HashMap<Object, Object>> hisbillsList = hisbillsHistoryService.findHisBillsByDate(searchMap);
|
||||
|
||||
|
||||
@@ -30,4 +30,6 @@ public interface HisDetailService {
|
||||
List<HashMap<Object, Object>> findHisCashDetail(HashMap<Object, Object> map) throws Exception;
|
||||
|
||||
List<HashMap<Object, Object>> findHisDetailCountData(HashMap<Object, Object> map) throws Exception;
|
||||
|
||||
List<HashMap<Object, Object>> findMedicalInsuranceGroupData(HashMap<Object, Object> map) throws Exception;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.saye.hospitalgd.service;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author thuang
|
||||
* @version 1.0
|
||||
* @description: 医保对账Service
|
||||
* @date 2025/10/24
|
||||
*/
|
||||
public interface MedicalInsuranceReconciliationService {
|
||||
|
||||
/**
|
||||
* 插入医保对账结果
|
||||
*/
|
||||
void insertMedicalInsuranceReconciliationResult(HashMap<Object, Object> map) throws Exception;
|
||||
|
||||
/**
|
||||
* 批量插入医保对账结果
|
||||
*/
|
||||
void insertMedicalInsuranceReconciliationResultBatch(List<HashMap<Object, Object>> list) throws Exception;
|
||||
|
||||
/**
|
||||
* 查询医保对账结果
|
||||
*/
|
||||
List<HashMap<Object, Object>> findMedicalInsuranceReconciliationResult(HashMap<Object, Object> map) throws Exception;
|
||||
|
||||
/**
|
||||
* 删除医保对账结果
|
||||
*/
|
||||
void deleteMedicalInsuranceReconciliationResult(HashMap<Object, Object> map) throws Exception;
|
||||
}
|
||||
|
||||
|
||||
@@ -179,5 +179,9 @@ public class HisDetailServiceImpl implements HisDetailService {
|
||||
return hisDetailMapper.findHisDetailCountData(map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<HashMap<Object, Object>> findMedicalInsuranceGroupData(HashMap<Object, Object> map) throws Exception {
|
||||
return hisDetailMapper.findMedicalInsuranceGroupData(map);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.saye.hospitalgd.service.impl;
|
||||
|
||||
import com.saye.hospitalgd.mapper.MedicalInsuranceReconciliationMapper;
|
||||
import com.saye.hospitalgd.service.MedicalInsuranceReconciliationService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author thuang
|
||||
* @version 1.0
|
||||
* @description: 医保对账ServiceImpl
|
||||
* @date 2025/10/24
|
||||
*/
|
||||
@Service
|
||||
@Transactional
|
||||
public class MedicalInsuranceReconciliationServiceImpl implements MedicalInsuranceReconciliationService {
|
||||
|
||||
@Autowired
|
||||
private MedicalInsuranceReconciliationMapper medicalInsuranceReconciliationMapper;
|
||||
|
||||
@Override
|
||||
public void insertMedicalInsuranceReconciliationResult(HashMap<Object, Object> map) throws Exception {
|
||||
medicalInsuranceReconciliationMapper.insertMedicalInsuranceReconciliationResult(map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertMedicalInsuranceReconciliationResultBatch(List<HashMap<Object, Object>> list) throws Exception {
|
||||
medicalInsuranceReconciliationMapper.insertMedicalInsuranceReconciliationResultBatch(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<HashMap<Object, Object>> findMedicalInsuranceReconciliationResult(HashMap<Object, Object> map) throws Exception {
|
||||
return medicalInsuranceReconciliationMapper.findMedicalInsuranceReconciliationResult(map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteMedicalInsuranceReconciliationResult(HashMap<Object, Object> map) throws Exception {
|
||||
medicalInsuranceReconciliationMapper.deleteMedicalInsuranceReconciliationResult(map);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -76,4 +76,5 @@ public interface FinanceUserService {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -106,4 +106,5 @@ public class FinanceUserServiceImpl implements FinanceUserService {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -765,6 +765,20 @@ public class HisUtil {
|
||||
powerTranID = powerTranIDElm.getText();
|
||||
}
|
||||
|
||||
//清算类别(医保记录才有)
|
||||
Element clrTypeElm = item.element("clr_type");
|
||||
String clrType = "";
|
||||
if (clrTypeElm != null) {
|
||||
clrType = clrTypeElm.getText();
|
||||
}
|
||||
|
||||
//险种类型(医保记录才有)
|
||||
Element insutypeElm = item.element("insutype");
|
||||
String insutype = "";
|
||||
if (insutypeElm != null) {
|
||||
insutype = insutypeElm.getText();
|
||||
}
|
||||
|
||||
addMap.put("visitzOrg", visitzOrg);
|
||||
addMap.put("bizType", bizType);
|
||||
addMap.put("payType", payType);
|
||||
@@ -782,7 +796,9 @@ public class HisUtil {
|
||||
addMap.put("hisTime", hisTime);
|
||||
addMap.put("hisOperCode", hisOperNum); // 修改字段名以匹配HISGetDataMethodByJH中的使用
|
||||
addMap.put("powerTranID", powerTranID);
|
||||
addMap.put("hisTransId", receiptNO); // 新增HisTransId字段,使用ReceiptNO的值
|
||||
addMap.put("hisTransId", receiptNO);
|
||||
addMap.put("clrType", clrType); // 清算类别
|
||||
addMap.put("insutype", insutype); // 险种类型 // 新增HisTransId字段,使用ReceiptNO的值
|
||||
|
||||
addList.add(addMap);
|
||||
}
|
||||
|
||||
@@ -208,4 +208,5 @@ public class HttpClientUtil {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
114
src/main/java/com/saye/hospitalgd/util/SSLUtil.java
Normal file
114
src/main/java/com/saye/hospitalgd/util/SSLUtil.java
Normal file
@@ -0,0 +1,114 @@
|
||||
package com.saye.hospitalgd.util;
|
||||
|
||||
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
||||
import org.apache.http.conn.ssl.TrustStrategy;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.ssl.SSLContextBuilder;
|
||||
|
||||
import javax.net.ssl.*;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
/**
|
||||
* SSL证书工具类
|
||||
* 用于处理HTTPS请求时的SSL证书验证问题
|
||||
*
|
||||
* @author thuang
|
||||
* @date 2025/10/24
|
||||
*/
|
||||
public class SSLUtil {
|
||||
|
||||
/**
|
||||
* 创建一个信任所有证书的HttpClient
|
||||
* 注意:此方法会跳过SSL证书验证,仅用于开发/测试环境
|
||||
* 生产环境建议导入正确的SSL证书到JVM信任库
|
||||
*
|
||||
* @return CloseableHttpClient
|
||||
* @throws KeyStoreException
|
||||
* @throws NoSuchAlgorithmException
|
||||
* @throws KeyManagementException
|
||||
*/
|
||||
public static CloseableHttpClient createSSLClientDefault()
|
||||
throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
|
||||
|
||||
// 创建信任所有证书的策略
|
||||
TrustStrategy acceptingTrustStrategy = new TrustStrategy() {
|
||||
@Override
|
||||
public boolean isTrusted(X509Certificate[] chain, String authType)
|
||||
throws CertificateException {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// 构建SSL上下文
|
||||
SSLContext sslContext = SSLContextBuilder
|
||||
.create()
|
||||
.loadTrustMaterial(null, acceptingTrustStrategy)
|
||||
.build();
|
||||
|
||||
// 创建SSL连接工厂(不验证主机名)
|
||||
SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(
|
||||
sslContext,
|
||||
new String[]{"TLSv1", "TLSv1.1", "TLSv1.2", "SSLv3"},
|
||||
null,
|
||||
SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER
|
||||
);
|
||||
|
||||
// 创建HttpClient
|
||||
return HttpClients.custom()
|
||||
.setSSLSocketFactory(sslSocketFactory)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 全局禁用SSL证书验证(针对HttpsURLConnection)
|
||||
* 注意:此方法会影响整个JVM,请谨慎使用
|
||||
*/
|
||||
public static void disableSSLVerification() {
|
||||
try {
|
||||
// 创建信任所有证书的TrustManager
|
||||
TrustManager[] trustAllCerts = new TrustManager[]{
|
||||
new X509TrustManager() {
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] certs, String authType) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] certs, String authType) {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 安装信任所有证书的TrustManager
|
||||
SSLContext sc = SSLContext.getInstance("SSL");
|
||||
sc.init(null, trustAllCerts, new java.security.SecureRandom());
|
||||
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
|
||||
|
||||
// 创建不进行主机名验证的HostnameVerifier
|
||||
HostnameVerifier allHostsValid = new HostnameVerifier() {
|
||||
@Override
|
||||
public boolean verify(String hostname, SSLSession session) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// 安装不进行主机名验证的HostnameVerifier
|
||||
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
|
||||
|
||||
} catch (NoSuchAlgorithmException | KeyManagementException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
<result column="QUARTZ_GROUP" property="quartzGroup" jdbcType="VARCHAR" />
|
||||
<result column="STATUS" property="status" jdbcType="VARCHAR" />
|
||||
<result column="QUARTZ_CLASS" property="quartzClass" jdbcType="VARCHAR" />
|
||||
<result column="QUARTZ_TYPE" property="quartzType" jdbcType="VARCHAR" />
|
||||
<result column="REMARK" property="remark" jdbcType="VARCHAR" />
|
||||
<result column="CREATEUSERID" property="createUserId" jdbcType="VARCHAR" />
|
||||
<result column="EXPRESSION" property="expression" jdbcType="VARCHAR" />
|
||||
@@ -16,12 +17,15 @@
|
||||
|
||||
<!-- 查询所有任务 -->
|
||||
<select id="findAll" parameterType="HashMap" resultMap="BaseResultMap">
|
||||
select bqc.CONFIGID,bqc.QUARTZ_NAME,bqc.QUARTZ_GROUP,bqc.STATUS,bqc.QUARTZ_CLASS,bqc.REMARK,bqc.CREATEUSERID,bqc.EXPRESSION,bqc.CREATE_TIME from base_quartz_config bqc
|
||||
select bqc.CONFIGID,bqc.QUARTZ_NAME,bqc.QUARTZ_GROUP,bqc.STATUS,bqc.QUARTZ_CLASS,bqc.QUARTZ_TYPE,bqc.REMARK,bqc.CREATEUSERID,bqc.EXPRESSION,bqc.CREATE_TIME from base_quartz_config bqc
|
||||
<where>
|
||||
<if test="part_name!=null and part_name!=''">
|
||||
<if test="quartz_name!=null and quartz_name!=''">
|
||||
and bqc.QUARTZ_NAME like concat('%',concat(#{quartz_name},'%'))
|
||||
</if>
|
||||
<if test="part_type!=null and part_type!=''">
|
||||
<if test="quartz_type!=null and quartz_type!=''">
|
||||
and bqc.QUARTZ_TYPE = #{quartz_type}
|
||||
</if>
|
||||
<if test="configId!=null and configId!=''">
|
||||
and bqc.CONFIGID = #{configId}
|
||||
</if>
|
||||
</where>
|
||||
@@ -30,14 +34,14 @@
|
||||
|
||||
<!-- 根据id查询定时任务 -->
|
||||
<select id="findEntityById" resultMap="BaseResultMap">
|
||||
select CONFIGID,QUARTZ_NAME,QUARTZ_GROUP,STATUS,QUARTZ_CLASS,REMARK,CREATEUSERID,EXPRESSION,CREATE_TIME from base_quartz_config
|
||||
select CONFIGID,QUARTZ_NAME,QUARTZ_GROUP,STATUS,QUARTZ_CLASS,QUARTZ_TYPE,REMARK,CREATEUSERID,EXPRESSION,CREATE_TIME from base_quartz_config
|
||||
where CONFIGID=#{id}
|
||||
</select>
|
||||
|
||||
<!-- 更新定时任务 -->
|
||||
<update id="updateQuartzConfigByEntity" parameterType="com.saye.hospitalgd.model.BaseQuartzConfigEntity">
|
||||
update base_quartz_config set QUARTZ_NAME=#{quartzName},QUARTZ_GROUP=#{quartzGroup},STATUS=#{status},QUARTZ_CLASS=#{quartzClass}
|
||||
,REMARK=#{remark},CREATEUSERID=#{createUserId},EXPRESSION=#{expression}
|
||||
,QUARTZ_TYPE=#{quartzType},REMARK=#{remark},CREATEUSERID=#{createUserId},EXPRESSION=#{expression}
|
||||
where CONFIGID=#{configId}
|
||||
</update>
|
||||
|
||||
@@ -53,14 +57,14 @@
|
||||
|
||||
<!-- 添加定时任务 -->
|
||||
<insert id="addQuartz" parameterType="hashMap">
|
||||
insert into base_quartz_config(configid, quartz_name, status, quartz_class, remark, createuserid, expression, create_time)
|
||||
values(#{id},#{quartzName},#{status}, #{quartz_class}, #{remark}, #{createuserid}, #{expression}, #{create_time} )
|
||||
insert into base_quartz_config(configid, quartz_name, status, quartz_class, quartz_type, remark, createuserid, expression, create_time)
|
||||
values(#{id},#{quartzName},#{status}, #{quartz_class}, #{quartz_type}, #{remark}, #{createuserid}, #{expression}, #{create_time} )
|
||||
</insert>
|
||||
|
||||
<!-- 更新定时任务信息 -->
|
||||
<update id="updateQuartzConfigById">
|
||||
update base_quartz_config set QUARTZ_NAME=#{quartzName},QUARTZ_GROUP=#{quartzGroup},QUARTZ_CLASS=#{quartzClass}
|
||||
,REMARK=#{remark},EXPRESSION=#{expression}
|
||||
,QUARTZ_TYPE=#{quartzType},REMARK=#{remark},EXPRESSION=#{expression}
|
||||
where CONFIGID=#{configId}
|
||||
</update>
|
||||
|
||||
|
||||
@@ -17,6 +17,10 @@
|
||||
,trade_date
|
||||
,his_wsdl_id
|
||||
,HisTransId
|
||||
,clr_type
|
||||
,insutype
|
||||
,ybzhAmount
|
||||
,ybtcAmount
|
||||
from hisbill_history
|
||||
<where>
|
||||
<if test="payType!=null and payType!=''">
|
||||
@@ -97,24 +101,25 @@
|
||||
|
||||
<insert id="insertAllHisBillOriginalHY" parameterType="java.util.List">
|
||||
insert into
|
||||
hisbill_original_hy(VisitzOrg,BizType,PayType,Amount,ZFAmount,YBZHAmount,YBTCAmount,Receipt_no,PatientID,PatientName,TradeTime,HisTime,HisOperNum,PowerTranID,trade_date)
|
||||
hisbill_original_hy(VisitzOrg,BizType,PayType,Amount,ZFAmount,YBZHAmount,YBTCAmount,Receipt_no,PatientID,PatientName,TradeTime,HisTime,HisOperNum,PowerTranID,trade_date,clr_type,insutype)
|
||||
values
|
||||
<foreach collection="list" index="index" item="itm" separator=",">
|
||||
(
|
||||
#{itm.visitzOrg},#{itm.bizType},#{itm.payType},#{itm.amount},#{itm.zfAmount},#{itm.ybzhAmount},#{itm.ybtcAmount},
|
||||
#{itm.receiptNO},#{itm.patientID},#{itm.patientName},#{itm.tradeTime},#{itm.hisTime},#{itm.hisOperNum},#{itm.powerTranID},#{itm.trade_date}
|
||||
#{itm.receiptNO},#{itm.patientID},#{itm.patientName},#{itm.tradeTime},#{itm.hisTime},#{itm.hisOperNum},#{itm.powerTranID},#{itm.trade_date},
|
||||
#{itm.clrType},#{itm.insutype}
|
||||
)
|
||||
</foreach>
|
||||
</insert>
|
||||
|
||||
<insert id="insertAllHisBillHistory" parameterType="java.util.List">
|
||||
insert into
|
||||
hisbill_history(PayMethod,TradingStatus,BizType,PayType,TradeTime,HisOperCode,Amount,remarks,PlatformTransId,PatientId,PatientName,trade_date,his_wsdl_id,HisTransId)
|
||||
hisbill_history(PayMethod,TradingStatus,BizType,PayType,TradeTime,HisOperCode,Amount,remarks,PlatformTransId,PatientId,PatientName,trade_date,his_wsdl_id,HisTransId,clr_type,insutype,ybzhAmount,ybtcAmount)
|
||||
values
|
||||
<foreach collection="list" index="index" item="itm" separator=",">
|
||||
(
|
||||
#{itm.payMethod},#{itm.tradingStatus},#{itm.bizType},#{itm.payType},#{itm.tradeTime},#{itm.hisOperCode},#{itm.amount},#{itm.remarks},#{itm.platformTransId},#{itm.patientId}
|
||||
,#{itm.patientName},#{itm.trade_date},#{itm.his_wsdl_id},#{itm.hisTransId}
|
||||
,#{itm.patientName},#{itm.trade_date},#{itm.his_wsdl_id},#{itm.hisTransId},#{itm.clrType},#{itm.insutype},#{itm.ybzhAmount},#{itm.ybtcAmount}
|
||||
)
|
||||
</foreach>
|
||||
</insert>
|
||||
@@ -147,6 +152,10 @@
|
||||
,trade_date
|
||||
,his_wsdl_id
|
||||
,HisTransId
|
||||
,clr_type
|
||||
,insutype
|
||||
,ybzhAmount
|
||||
,ybtcAmount
|
||||
from hisbill_history
|
||||
where trade_date=#{trade_date}
|
||||
<if test="payType!=null and payType!=''">
|
||||
@@ -162,7 +171,7 @@
|
||||
|
||||
<select id="findHisDetailByTimeAndYSDDH" parameterType="HashMap" resultType="HashMap">
|
||||
select PayMethod,TradingStatus,BizType,PayType,TradeTime,HisOperCode,Amount,remarks,PlatformTransId,
|
||||
PatientId,PatientName,HisTransId
|
||||
PatientId,PatientName,HisTransId,clr_type,insutype,ybzhAmount,ybtcAmount
|
||||
from hisbill_history
|
||||
where trade_date=#{searchTime}
|
||||
and PlatformTransId = #{c_ysddh}
|
||||
@@ -177,7 +186,7 @@
|
||||
</select>
|
||||
|
||||
<select id="findHisCashDetail" parameterType="HashMap" resultType="HashMap">
|
||||
select PayMethod, TradingStatus, BizType, PayType, TradeTime, HisOperCode, Amount, remarks, PlatformTransId, PatientId, PatientName, trade_date, his_wsdl_id, HisTransId
|
||||
select PayMethod, TradingStatus, BizType, PayType, TradeTime, HisOperCode, Amount, remarks, PlatformTransId, PatientId, PatientName, trade_date, his_wsdl_id, HisTransId, clr_type, insutype, ybzhAmount, ybtcAmount
|
||||
from hisbill_history
|
||||
where trade_date=#{trade_date} and PayType='5'
|
||||
</select>
|
||||
@@ -200,4 +209,23 @@
|
||||
</if>
|
||||
</where>
|
||||
</select>
|
||||
|
||||
<!-- 医保对账:按险种和清算类别分组统计(不限制PayType) -->
|
||||
<select id="findMedicalInsuranceGroupData" parameterType="HashMap" resultType="HashMap">
|
||||
select
|
||||
insutype as INSUTYPE,
|
||||
clr_type as CLR_TYPE,
|
||||
count(1) as FIXMEDINS_SETL_CNT,
|
||||
cast(IFNULL(sum(Amount),0) as decimal(19,2)) as MEDFEE_SUMAMT,
|
||||
cast(IFNULL(sum(ybtcAmount),0) as decimal(19,2)) as FUND_PAY_SUMAMT,
|
||||
cast(IFNULL(sum(ybzhAmount),0) as decimal(19,2)) as ACCT_PAY
|
||||
from hisbill_history
|
||||
where trade_date = #{trade_date}
|
||||
and insutype is not null
|
||||
and insutype != ''
|
||||
and clr_type is not null
|
||||
and clr_type != ''
|
||||
group by insutype, clr_type
|
||||
order by insutype, clr_type
|
||||
</select>
|
||||
</mapper>
|
||||
@@ -27,6 +27,9 @@
|
||||
<if test="military_code != null and military_code != ''">
|
||||
and PayType != #{military_code}
|
||||
</if>
|
||||
<if test="medical_insurance_code != null and medical_insurance_code != ''">
|
||||
and PayType != #{medical_insurance_code}
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<select id="findHisDetailByParam" parameterType="HashMap" resultType="HashMap">
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.saye.hospitalgd.mapper.MedicalInsuranceReconciliationMapper">
|
||||
|
||||
<!-- ResultMap for proper field mapping -->
|
||||
<resultMap id="MedicalInsuranceResultMap" type="HashMap">
|
||||
<result column="id" property="id" jdbcType="VARCHAR"/>
|
||||
<result column="trade_date" property="trade_date" jdbcType="VARCHAR"/>
|
||||
<result column="insutype" property="insutype" jdbcType="VARCHAR"/>
|
||||
<result column="clr_type" property="clr_type" jdbcType="VARCHAR"/>
|
||||
<result column="medfee_sumamt" property="medfee_sumamt" jdbcType="DECIMAL"/>
|
||||
<result column="fund_pay_sumamt" property="fund_pay_sumamt" jdbcType="DECIMAL"/>
|
||||
<result column="acct_pay" property="acct_pay" jdbcType="DECIMAL"/>
|
||||
<result column="fixmedins_setl_cnt" property="fixmedins_setl_cnt" jdbcType="INTEGER"/>
|
||||
<result column="stmt_rslt" property="stmt_rslt" jdbcType="VARCHAR"/>
|
||||
<result column="stmt_rslt_dscr" property="stmt_rslt_dscr" jdbcType="VARCHAR"/>
|
||||
<result column="api_result" property="api_result" jdbcType="VARCHAR"/>
|
||||
<result column="create_time" property="create_time" jdbcType="VARCHAR"/>
|
||||
<result column="modify_time" property="modify_time" jdbcType="VARCHAR"/>
|
||||
</resultMap>
|
||||
|
||||
<!-- 插入医保对账结果 -->
|
||||
<insert id="insertMedicalInsuranceReconciliationResult" parameterType="HashMap">
|
||||
insert into medical_insurance_reconciliation_result (
|
||||
id, trade_date, insutype, clr_type,
|
||||
medfee_sumamt, fund_pay_sumamt, acct_pay, fixmedins_setl_cnt,
|
||||
stmt_rslt, stmt_rslt_dscr, api_result,
|
||||
create_time, modify_time
|
||||
) values (
|
||||
#{id}, #{trade_date}, #{insutype}, #{clr_type},
|
||||
#{medfee_sumamt}, #{fund_pay_sumamt}, #{acct_pay}, #{fixmedins_setl_cnt},
|
||||
#{stmt_rslt}, #{stmt_rslt_dscr}, #{api_result},
|
||||
#{create_time}, #{modify_time}
|
||||
)
|
||||
</insert>
|
||||
|
||||
<!-- 批量插入医保对账结果 -->
|
||||
<insert id="insertMedicalInsuranceReconciliationResultBatch" parameterType="java.util.List">
|
||||
insert into medical_insurance_reconciliation_result (
|
||||
id, trade_date, insutype, clr_type,
|
||||
medfee_sumamt, fund_pay_sumamt, acct_pay, fixmedins_setl_cnt,
|
||||
stmt_rslt, stmt_rslt_dscr, api_result,
|
||||
create_time, modify_time
|
||||
) values
|
||||
<foreach collection="list" index="index" item="itm" separator=",">
|
||||
(
|
||||
#{itm.id}, #{itm.trade_date}, #{itm.insutype}, #{itm.clr_type},
|
||||
#{itm.medfee_sumamt}, #{itm.fund_pay_sumamt}, #{itm.acct_pay}, #{itm.fixmedins_setl_cnt},
|
||||
#{itm.stmt_rslt}, #{itm.stmt_rslt_dscr}, #{itm.api_result},
|
||||
#{itm.create_time}, #{itm.modify_time}
|
||||
)
|
||||
</foreach>
|
||||
</insert>
|
||||
|
||||
<!-- 查询医保对账结果 -->
|
||||
<select id="findMedicalInsuranceReconciliationResult" parameterType="HashMap" resultMap="MedicalInsuranceResultMap">
|
||||
select
|
||||
id,
|
||||
trade_date,
|
||||
insutype,
|
||||
clr_type,
|
||||
medfee_sumamt,
|
||||
fund_pay_sumamt,
|
||||
acct_pay,
|
||||
fixmedins_setl_cnt,
|
||||
stmt_rslt,
|
||||
stmt_rslt_dscr,
|
||||
api_result,
|
||||
DATE_FORMAT(create_time, '%Y-%m-%d %H:%i:%s') as create_time,
|
||||
DATE_FORMAT(modify_time, '%Y-%m-%d %H:%i:%s') as modify_time
|
||||
from medical_insurance_reconciliation_result
|
||||
<where>
|
||||
<if test="trade_date != null and trade_date != ''">
|
||||
and trade_date = #{trade_date}
|
||||
</if>
|
||||
<if test="startDate != null and startDate != ''">
|
||||
and trade_date >= #{startDate}
|
||||
</if>
|
||||
<if test="endDate != null and endDate != ''">
|
||||
and trade_date <= #{endDate}
|
||||
</if>
|
||||
<if test="insutype != null and insutype != ''">
|
||||
and insutype = #{insutype}
|
||||
</if>
|
||||
<if test="clr_type != null and clr_type != ''">
|
||||
and clr_type = #{clr_type}
|
||||
</if>
|
||||
<if test="clrType != null and clrType != ''">
|
||||
and clr_type = #{clrType}
|
||||
</if>
|
||||
<if test="stmt_rslt != null and stmt_rslt != ''">
|
||||
and stmt_rslt = #{stmt_rslt}
|
||||
</if>
|
||||
<if test="stmtRslt != null and stmtRslt != ''">
|
||||
and stmt_rslt = #{stmtRslt}
|
||||
</if>
|
||||
</where>
|
||||
order by create_time desc, trade_date desc, insutype, clr_type
|
||||
</select>
|
||||
|
||||
<!-- 删除医保对账结果 -->
|
||||
<delete id="deleteMedicalInsuranceReconciliationResult" parameterType="HashMap">
|
||||
delete from medical_insurance_reconciliation_result
|
||||
where trade_date = #{trade_date}
|
||||
</delete>
|
||||
|
||||
</mapper>
|
||||
|
||||
|
||||
@@ -128,4 +128,5 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,476 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>医保对账结果查询</title>
|
||||
<link rel="stylesheet" th:href="@{/layui/css/layui.css}">
|
||||
<link rel="stylesheet" th:href="@{/css/common.css}">
|
||||
<!-- 引入组件库 -->
|
||||
<script th:src="@{/layui/jquery-3.4.1.min.js}"></script>
|
||||
<script th:src="@{/layui/layui.js}"></script>
|
||||
<script th:src="@{/js/common.js}"></script>
|
||||
|
||||
<style>
|
||||
body {
|
||||
background: #f2f2f2
|
||||
}
|
||||
|
||||
#boxDiv {
|
||||
background: #ffffff
|
||||
}
|
||||
|
||||
#titleDiv {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
.tableTitle {
|
||||
height: 20px;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.tableTitle > * {
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
display: inline-block;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.tableName {
|
||||
border-left: 3px solid #0000FF;
|
||||
padding-left: 5px;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.selectDate {
|
||||
font-size: 14px;
|
||||
color: rgba(0, 0, 0, 0.65)
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="layui-layout-body">
|
||||
<div id="boxDiv" style="left:8px;right: 8px;bottom:8px;top:8px;position:absolute;">
|
||||
<div class="toolbar" id="titleDiv">
|
||||
<div style="display: inline-block;">
|
||||
<form class="layui-form">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">日期选择</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" class="layui-input formWidthTwo" id="searchDate" placeholder=" ~ ">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">险种类型</label>
|
||||
<div class="layui-input-inline">
|
||||
<select id="insutype" class="layui-input formWidth">
|
||||
<option value="">全部</option>
|
||||
<option value="310">职工基本医疗保险</option>
|
||||
<option value="390">城乡居民基本医疗保险</option>
|
||||
<option value="510">公务员医疗补助</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">清算类别</label>
|
||||
<div class="layui-input-inline">
|
||||
<select id="clrType" class="layui-input formWidth">
|
||||
<option value="">全部</option>
|
||||
<option value="11">普通门诊</option>
|
||||
<option value="21">住院</option>
|
||||
<option value="31">门诊慢特病</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">对账结果</label>
|
||||
<div class="layui-input-inline">
|
||||
<select id="stmtRslt" class="layui-input formWidth">
|
||||
<option value="">全部</option>
|
||||
<option value="0">平</option>
|
||||
<option value="1">不平</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" data-type="search" id="search" onclick="search()">
|
||||
<i class="layui-icon layui-icon-search"></i>查询
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-warm" onclick="executeReconciliation()">
|
||||
<i class="layui-icon layui-icon-refresh"></i>执行对账
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" onclick="exportExcel()">
|
||||
<i class="layui-icon"></i>导出
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="tableTitle">
|
||||
<span class="tableName">医保对账结果</span>
|
||||
<span class="selectDate"> </span>
|
||||
</div>
|
||||
<table id="demo" lay-filter="test"></table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 详情弹窗 -->
|
||||
<div id="detailDialog" style="display:none; padding: 20px;">
|
||||
<table class="layui-table" lay-skin="line">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="width: 150px; font-weight: bold;">对账日期</td>
|
||||
<td id="detail_trade_date"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="font-weight: bold;">险种类型</td>
|
||||
<td id="detail_insutype"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="font-weight: bold;">清算类别</td>
|
||||
<td id="detail_clr_type"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="font-weight: bold;">医疗费用总额</td>
|
||||
<td id="detail_medfee_sumamt"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="font-weight: bold;">基金支付总额</td>
|
||||
<td id="detail_fund_pay_sumamt"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="font-weight: bold;">账户支付金额</td>
|
||||
<td id="detail_acct_pay"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="font-weight: bold;">结算笔数</td>
|
||||
<td id="detail_fixmedins_setl_cnt"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="font-weight: bold;">对账结果</td>
|
||||
<td id="detail_stmt_rslt"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="font-weight: bold;">对账结果描述</td>
|
||||
<td id="detail_stmt_rslt_dscr"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="font-weight: bold;">接口调用结果</td>
|
||||
<td id="detail_api_result"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="font-weight: bold;">创建时间</td>
|
||||
<td id="detail_create_time"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="barDemo">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="getInfo">详细信息</a>
|
||||
</script>
|
||||
</body>
|
||||
<script th:inline="javascript">
|
||||
let layer, laydate, table, form;
|
||||
|
||||
layui.use(['element', 'table', 'laydate', 'layer', 'form'], function () {
|
||||
layer = layui.layer;
|
||||
table = layui.table;
|
||||
laydate = layui.laydate;
|
||||
form = layui.form;
|
||||
|
||||
//表格加载
|
||||
table.render({
|
||||
elem: '#demo',
|
||||
height: 'full-' + ($(".toolbar").height() + 60),
|
||||
url: '/medicalInsuranceReconciliation/findMedicalInsuranceReconciliationResult',
|
||||
title: '医保对账结果记录',
|
||||
page: true,//开启分页
|
||||
limit: 20,
|
||||
limits: [20, 30, 50],
|
||||
defaultToolbar: [],
|
||||
id: 'test',
|
||||
even: 'true',
|
||||
cols: [
|
||||
[
|
||||
{type: 'numbers', title: '序号', width: 60},
|
||||
{field: 'trade_date', title: '对账日期', align: 'center', width: 120},
|
||||
{field: 'insutype', title: '险种类型', align: 'center', width: 100, templet: function(d){
|
||||
if(d.insutype === '310') return '职工医保';
|
||||
if(d.insutype === '390') return '居民医保';
|
||||
if(d.insutype === '510') return '公务员补助';
|
||||
return d.insutype;
|
||||
}},
|
||||
{field: 'clr_type', title: '清算类别', align: 'center', width: 100, templet: function(d){
|
||||
if(d.clr_type === '11') return '普通门诊';
|
||||
if(d.clr_type === '21') return '住院';
|
||||
if(d.clr_type === '31') return '门诊慢特病';
|
||||
return d.clr_type;
|
||||
}},
|
||||
{field: 'medfee_sumamt', title: '医疗费用总额', align: 'center', width: 130},
|
||||
{field: 'fund_pay_sumamt', title: '基金支付总额', align: 'center', width: 130},
|
||||
{field: 'acct_pay', title: '账户支付金额', align: 'center', width: 130},
|
||||
{field: 'fixmedins_setl_cnt', title: '结算笔数', align: 'center', width: 100},
|
||||
{field: 'stmt_rslt', title: '对账结果', align: 'center', width: 100, templet: function(d){
|
||||
if(d.stmt_rslt === '0') {
|
||||
return '<span style="color: green;">平</span>';
|
||||
} else if(d.stmt_rslt === '1') {
|
||||
return '<span style="color: red;">不平</span>';
|
||||
} else {
|
||||
return '<span style="color: orange;">异常</span>';
|
||||
}
|
||||
}},
|
||||
{field: 'create_time', title: '创建时间', align: 'center', width: 160},
|
||||
{title: '操作', align: 'center', width: 120, toolbar: '#barDemo', fixed: 'right'},
|
||||
]
|
||||
],
|
||||
done: function (res, curr, count) {
|
||||
// 表格加载完成后的回调
|
||||
}
|
||||
});
|
||||
|
||||
//时间控件
|
||||
laydate.render({
|
||||
elem: '#searchDate',
|
||||
type: 'date',
|
||||
range: '~',
|
||||
done: function(value, date, endDate) {
|
||||
console.log("laydate选择完成:", value); // 调试日志
|
||||
}
|
||||
});
|
||||
|
||||
// 表格工具栏事件
|
||||
table.on('tool(test)', function (obj) {
|
||||
let data = obj.data;
|
||||
|
||||
if (obj.event === 'getInfo') {
|
||||
showDetail(data);
|
||||
}
|
||||
});
|
||||
|
||||
// 初始化:设置默认日期为前一天
|
||||
let yesterday = getYesterdayDate();
|
||||
console.log("初始化前一天日期:", yesterday); // 调试日志
|
||||
|
||||
// 直接设置日期值
|
||||
$("#searchDate").val(yesterday + " ~ " + yesterday);
|
||||
|
||||
// 确保DOM更新后再查询
|
||||
setTimeout(function() {
|
||||
let currentVal = $("#searchDate").val();
|
||||
console.log("延迟执行查询,当前日期输入框值:", currentVal);
|
||||
|
||||
// 如果日期设置失败,强制设置
|
||||
if (!currentVal || currentVal.indexOf("~") === -1) {
|
||||
console.log("日期设置失败,强制重新设置");
|
||||
$("#searchDate").val(yesterday + " ~ " + yesterday);
|
||||
}
|
||||
|
||||
search();
|
||||
}, 200);
|
||||
});
|
||||
|
||||
// 查询
|
||||
function search(num) {
|
||||
num = num === null ? 1 : num;
|
||||
let url = "/medicalInsuranceReconciliation/findMedicalInsuranceReconciliationResult";
|
||||
let param = {};
|
||||
|
||||
let date = $("#searchDate").val();
|
||||
console.log("搜索日期:", date); // 调试日志
|
||||
|
||||
if (date !== '' && date.indexOf("~") > -1) {
|
||||
let time = date.split("~");
|
||||
let startDate = time[0].trim();
|
||||
let endDate = time[1].trim();
|
||||
|
||||
param.startDate = startDate;
|
||||
param.endDate = endDate;
|
||||
|
||||
console.log("日期参数:", param); // 调试日志
|
||||
$(".selectDate").text(startDate + " ~ " + endDate);
|
||||
} else if (date !== '' && date.indexOf("~") === -1) {
|
||||
// 如果只有一个日期,设置为当天
|
||||
param.startDate = date.trim();
|
||||
param.endDate = date.trim();
|
||||
console.log("单日期参数:", param); // 调试日志
|
||||
$(".selectDate").text(date + " ~ " + date);
|
||||
} else {
|
||||
// 如果没有日期,默认使用前一天
|
||||
let yesterday = getYesterdayDate();
|
||||
param.startDate = yesterday;
|
||||
param.endDate = yesterday;
|
||||
console.log("默认前一天参数:", param); // 调试日志
|
||||
$(".selectDate").text(yesterday + " ~ " + yesterday);
|
||||
// 同时更新输入框
|
||||
$("#searchDate").val(yesterday + " ~ " + yesterday);
|
||||
}
|
||||
|
||||
// 确保至少有日期参数,防止查询所有数据
|
||||
if (!param.startDate || !param.endDate) {
|
||||
let yesterday = getYesterdayDate();
|
||||
param.startDate = yesterday;
|
||||
param.endDate = yesterday;
|
||||
console.log("强制设置前一天参数:", param); // 调试日志
|
||||
}
|
||||
|
||||
let insutype = $("#insutype").val();
|
||||
if (insutype !== '') {
|
||||
param.insutype = insutype;
|
||||
}
|
||||
|
||||
let clrType = $("#clrType").val();
|
||||
if (clrType !== '') {
|
||||
param.clrType = clrType;
|
||||
}
|
||||
|
||||
let stmtRslt = $("#stmtRslt").val();
|
||||
if (stmtRslt !== '') {
|
||||
param.stmtRslt = stmtRslt;
|
||||
}
|
||||
|
||||
table.reload('test', {
|
||||
method: 'get',
|
||||
url: url,
|
||||
where: param,
|
||||
page: {
|
||||
curr: num
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 执行医保对账
|
||||
function executeReconciliation() {
|
||||
layer.prompt({
|
||||
title: '请输入对账日期',
|
||||
formType: 0,
|
||||
value: getCurrentDate(),
|
||||
btn: ['确定', '取消']
|
||||
}, function(value, index, elem){
|
||||
layer.close(index);
|
||||
|
||||
let load = layer.load(1, {shade: [0.3, '#000']});
|
||||
|
||||
$.ajax({
|
||||
url: '/medicalInsuranceReconciliation/executeMedicalInsuranceReconciliation',
|
||||
type: 'POST',
|
||||
data: {
|
||||
trade_date: value
|
||||
},
|
||||
success: function(data) {
|
||||
layer.close(load);
|
||||
if(data.code === 0) {
|
||||
layer.msg('对账执行成功!', {icon: 1, time: 2000}, function(){
|
||||
search();
|
||||
});
|
||||
} else {
|
||||
layer.alert('对账执行失败:' + data.msg, {icon: 2});
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
layer.close(load);
|
||||
layer.alert('对账执行失败,请检查网络连接!', {icon: 2});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 显示详情
|
||||
function showDetail(data) {
|
||||
$("#detail_trade_date").text(data.trade_date || '-');
|
||||
|
||||
let insutypeText = data.insutype;
|
||||
if(data.insutype === '310') insutypeText = '310-职工基本医疗保险';
|
||||
if(data.insutype === '390') insutypeText = '390-城乡居民基本医疗保险';
|
||||
if(data.insutype === '510') insutypeText = '510-公务员医疗补助';
|
||||
$("#detail_insutype").text(insutypeText || '-');
|
||||
|
||||
let clrTypeText = data.clr_type;
|
||||
if(data.clr_type === '11') clrTypeText = '11-普通门诊';
|
||||
if(data.clr_type === '21') clrTypeText = '21-住院';
|
||||
if(data.clr_type === '31') clrTypeText = '31-门诊慢特病';
|
||||
$("#detail_clr_type").text(clrTypeText || '-');
|
||||
|
||||
$("#detail_medfee_sumamt").text(data.medfee_sumamt || '0.00');
|
||||
$("#detail_fund_pay_sumamt").text(data.fund_pay_sumamt || '0.00');
|
||||
$("#detail_acct_pay").text(data.acct_pay || '0.00');
|
||||
$("#detail_fixmedins_setl_cnt").text(data.fixmedins_setl_cnt || '0');
|
||||
|
||||
let stmtRsltText = data.stmt_rslt === '0' ? '平' : (data.stmt_rslt === '1' ? '不平' : '异常');
|
||||
$("#detail_stmt_rslt").html('<span style="color: ' + (data.stmt_rslt === '0' ? 'green' : 'red') + ';">' + stmtRsltText + '</span>');
|
||||
|
||||
$("#detail_stmt_rslt_dscr").text(data.stmt_rslt_dscr || '-');
|
||||
$("#detail_api_result").text(data.api_result || '-');
|
||||
$("#detail_create_time").text(data.create_time || '-');
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '医保对账详细信息',
|
||||
shade: 0.3,
|
||||
area: ['600px', '600px'],
|
||||
content: $("#detailDialog")
|
||||
});
|
||||
}
|
||||
|
||||
// 导出
|
||||
function exportExcel() {
|
||||
let url = "/medicalInsuranceReconciliation/exportMedicalInsuranceReconciliationResult";
|
||||
let param = {};
|
||||
|
||||
let date = $("#searchDate").val();
|
||||
if (date !== '') {
|
||||
let time = date.split("~");
|
||||
param.startDate = time[0].trim();
|
||||
param.endDate = time[1].trim();
|
||||
}
|
||||
|
||||
param.insutype = $("#insutype").val();
|
||||
param.clrType = $("#clrType").val();
|
||||
param.stmtRslt = $("#stmtRslt").val();
|
||||
|
||||
let dowloadName = "医保对账结果";
|
||||
param.dowloadName = dowloadName;
|
||||
|
||||
let load = layer.load();
|
||||
AjaxPostJson(url, param, function (data) {
|
||||
layer.close(load);
|
||||
if (data.errCode === "0") {
|
||||
let fileName = data.dlName;
|
||||
location.href = '/download?fileName=' + fileName + '&dowloadName=' + dowloadName;
|
||||
} else {
|
||||
layer.alert(data.errMsg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 获取当前日期(格式:yyyy-MM-dd)
|
||||
function getCurrentDate() {
|
||||
let date = new Date();
|
||||
let year = date.getFullYear();
|
||||
let month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
let day = String(date.getDate()).padStart(2, '0');
|
||||
return year + '-' + month + '-' + day;
|
||||
}
|
||||
|
||||
// 获取前一天日期(格式:yyyy-MM-dd)
|
||||
function getYesterdayDate() {
|
||||
let date = new Date();
|
||||
date.setDate(date.getDate() - 1); // 减一天
|
||||
let year = date.getFullYear();
|
||||
let month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
let day = String(date.getDate()).padStart(2, '0');
|
||||
return year + '-' + month + '-' + day;
|
||||
}
|
||||
</script>
|
||||
</html>
|
||||
|
||||
|
||||
@@ -73,4 +73,5 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
510
src/main/resources/templates/system/quartzManage.html
Normal file
510
src/main/resources/templates/system/quartzManage.html
Normal file
@@ -0,0 +1,510 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>定时任务管理</title>
|
||||
<link rel="stylesheet" th:href="@{/layui/css/layui.css}">
|
||||
<link rel="stylesheet" th:href="@{/css/common.css}">
|
||||
<script th:src="@{/layui/jquery-3.4.1.min.js}"></script>
|
||||
<script th:src="@{/layui/layui.js}"></script>
|
||||
<script th:src="@{/js/common.js}"></script>
|
||||
<script th:src="@{/js/rules.js}"></script>
|
||||
|
||||
<style>
|
||||
body {
|
||||
background: #f2f2f2
|
||||
}
|
||||
|
||||
#boxDiv {
|
||||
background: #ffffff
|
||||
}
|
||||
|
||||
#titleDiv {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 0 8px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="layui-layout-body">
|
||||
<div id="boxDiv" style="left:8px;right: 8px;bottom:8px;top:8px;position:absolute;">
|
||||
<div class="toolbar" id="titleDiv">
|
||||
<div class="layui-inline">
|
||||
<span>任务名称:</span>
|
||||
<input type="text" id="searchName" placeholder="任务名称关键字" autocomplete="off" class="layui-input formWidth"/>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<span>任务类型:</span>
|
||||
<select id="searchType" class="layui-input formWidth">
|
||||
<option value="">全部</option>
|
||||
<option value="1">对账任务</option>
|
||||
<option value="2">数据同步</option>
|
||||
<option value="3">其他任务</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" data-type="search" id="search">
|
||||
<i class="layui-icon"></i>查询
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" data-type="add" id="add">
|
||||
<i class="layui-icon"></i>添加
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-warm" onclick="refreshJobList()">
|
||||
<i class="layui-icon layui-icon-refresh"></i>刷新任务状态
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table id="mainTable" lay-filter="quartzTable"></table>
|
||||
|
||||
<!-- 表格操作栏 -->
|
||||
<script type="text/html" id="barDemo">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="edit">编辑</a>
|
||||
{{# if(d.status === '0'){ }}
|
||||
<a class="layui-btn layui-btn-warm layui-btn-xs" lay-event="start">启动</a>
|
||||
{{# } else { }}
|
||||
<a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="pause">暂停</a>
|
||||
{{# } }}
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
|
||||
</script>
|
||||
|
||||
<!-- 状态列模板 -->
|
||||
<script type="text/html" id="statusTpl">
|
||||
{{# if(d.status === '0'){ }}
|
||||
<span style="color: #FF5722;">已暂停</span>
|
||||
{{# } else { }}
|
||||
<span style="color: #5FB878;">运行中</span>
|
||||
{{# } }}
|
||||
</script>
|
||||
|
||||
<!-- 新增/编辑任务弹窗 -->
|
||||
<div id="addQuartz" style="display:none;">
|
||||
<form class="layui-form" style="margin-top:20px; padding-right: 20px;" lay-filter="quartzForm">
|
||||
<input type="hidden" id="configId" name="configId"/>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">任务名称:</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" id="quartzName" name="quartzName" required lay-verify="required"
|
||||
autocomplete="off" placeholder="请输入任务名称" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">任务类型:</label>
|
||||
<div class="layui-input-block">
|
||||
<select id="jobType" name="jobType" lay-verify="required">
|
||||
<option value="">请选择任务类型</option>
|
||||
<option value="1">对账任务</option>
|
||||
<option value="2">数据同步</option>
|
||||
<option value="3">其他任务</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">任务类:</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" id="quartz_class" name="quartz_class" required lay-verify="required"
|
||||
autocomplete="off" placeholder="例如: com.saye.hospitalgd.scheduler.job.XXXJob"
|
||||
class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">执行时间:</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="timeType" value="cron" title="Cron表达式" checked>
|
||||
<input type="radio" name="timeType" value="simple" title="简单配置">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item" id="cronDiv">
|
||||
<label class="layui-form-label">Cron表达式:</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" id="cronExpression" name="cronExpression"
|
||||
autocomplete="off" placeholder="例如: 0 0 2 * * ? (每天凌晨2点执行)"
|
||||
class="layui-input">
|
||||
<div class="layui-form-mid layui-word-aux">
|
||||
<a href="javascript:void(0);" onclick="showCronHelp()">Cron表达式帮助</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item layui-hide" id="simpleDiv">
|
||||
<label class="layui-form-label">执行频率:</label>
|
||||
<div class="layui-input-inline" style="width: 80px;">
|
||||
<input type="number" id="intervalValue" name="intervalValue" value="1"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-input-inline" style="width: 120px;">
|
||||
<select id="intervalUnit" name="intervalUnit">
|
||||
<option value="hour">小时</option>
|
||||
<option value="day" selected>天</option>
|
||||
<option value="week">周</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">备注:</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea id="remark" name="remark" placeholder="请输入任务备注说明"
|
||||
class="layui-textarea"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Cron帮助弹窗 -->
|
||||
<div id="cronHelp" style="display:none; padding: 20px;">
|
||||
<div style="line-height: 1.8;">
|
||||
<p><strong>Cron表达式格式:</strong>秒 分 时 日 月 周 [年]</p>
|
||||
<p><strong>常用示例:</strong></p>
|
||||
<ul style="list-style: disc; padding-left: 30px;">
|
||||
<li><code>0 0 2 * * ?</code> - 每天凌晨2点执行</li>
|
||||
<li><code>0 0 0/1 * * ?</code> - 每小时执行一次</li>
|
||||
<li><code>0 0 12 * * ?</code> - 每天中午12点执行</li>
|
||||
<li><code>0 0 1 1 * ?</code> - 每月1号凌晨1点执行</li>
|
||||
<li><code>0 0 23 ? * MON-FRI</code> - 周一到周五晚上11点执行</li>
|
||||
<li><code>0 0/30 * * * ?</code> - 每30分钟执行一次</li>
|
||||
</ul>
|
||||
<p><strong>特殊字符说明:</strong></p>
|
||||
<ul style="list-style: disc; padding-left: 30px;">
|
||||
<li><code>*</code> - 任意值</li>
|
||||
<li><code>?</code> - 不指定值(用于日和周)</li>
|
||||
<li><code>-</code> - 范围(例如:10-12)</li>
|
||||
<li><code>,</code> - 多个值(例如:MON,WED,FRI)</li>
|
||||
<li><code>/</code> - 递增(例如:0/15表示从0开始每15单位)</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
<script>
|
||||
let element, table, laydate, layer, form;
|
||||
let isEditMode = false;
|
||||
|
||||
layui.use(['element', 'table', 'laydate', 'layer', 'form'], function () {
|
||||
element = layui.element;
|
||||
table = layui.table;
|
||||
laydate = layui.laydate;
|
||||
layer = layui.layer;
|
||||
form = layui.form;
|
||||
|
||||
//表格加载
|
||||
table.render({
|
||||
elem: '#mainTable',
|
||||
height: 'full-' + 58,
|
||||
url: '/quartzConfig/findQuartzConfig',
|
||||
title: '定时任务表',
|
||||
page: true,//开启分页
|
||||
limit: 20,
|
||||
limits: [20, 30, 50],
|
||||
defaultToolbar: [],
|
||||
id: 'quartzTable',
|
||||
cols: [
|
||||
[
|
||||
{type: 'numbers', title: '序号', width: 60},
|
||||
{field: 'quartzName', title: '任务名称', width: 200},
|
||||
{field: 'quartzClass', title: '任务类', minWidth: 300},
|
||||
{field: 'quartzType', title: '任务类型', width: 100, templet: function (d) {
|
||||
if (d.quartzType === '1') return '对账任务';
|
||||
if (d.quartzType === '2') return '数据同步';
|
||||
if (d.quartzType === '3') return '其他任务';
|
||||
return d.quartzType || '-';
|
||||
}},
|
||||
{field: 'expression', title: 'Cron表达式', width: 150},
|
||||
{field: 'status', title: '状态', width: 100, align: 'center', templet: '#statusTpl'},
|
||||
{field: 'createTime', title: '创建时间', width: 160},
|
||||
{fixed: 'right', title: '操作', align: 'center', width: 200, toolbar: '#barDemo'}
|
||||
]
|
||||
]
|
||||
});
|
||||
|
||||
// 查询
|
||||
$("#search").on('click', function () {
|
||||
search();
|
||||
});
|
||||
|
||||
// 新增
|
||||
$("#add").on('click', function () {
|
||||
isEditMode = false;
|
||||
form.val('quartzForm', {
|
||||
configId: '',
|
||||
quartzName: '',
|
||||
jobType: '',
|
||||
quartz_class: '',
|
||||
cronExpression: '0 0 2 * * ?',
|
||||
intervalValue: '1',
|
||||
intervalUnit: 'day',
|
||||
remark: ''
|
||||
});
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: "新增定时任务",
|
||||
shade: 0.3,
|
||||
area: ['600px', '90%'],
|
||||
offset: 'auto',
|
||||
content: $("#addQuartz"),
|
||||
btn: ['保存', '取消'],
|
||||
btnAlign: 'c',
|
||||
success: function () {
|
||||
form.render();
|
||||
},
|
||||
yes: function (index, layero) {
|
||||
saveQuartz(index);
|
||||
},
|
||||
btn2: function () {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 表格操作事件
|
||||
table.on('tool(quartzTable)', function (obj) {
|
||||
let data = obj.data;
|
||||
|
||||
if (obj.event === 'edit') {
|
||||
editQuartz(data);
|
||||
} else if (obj.event === 'start') {
|
||||
changeStatus(data.id, '1');
|
||||
} else if (obj.event === 'pause') {
|
||||
changeStatus(data.id, '0');
|
||||
} else if (obj.event === 'del') {
|
||||
deleteQuartz(data.id);
|
||||
}
|
||||
});
|
||||
|
||||
// 监听时间类型切换
|
||||
form.on('radio(timeType)', function (data) {
|
||||
if (data.value === 'cron') {
|
||||
$('#cronDiv').removeClass('layui-hide');
|
||||
$('#simpleDiv').addClass('layui-hide');
|
||||
} else {
|
||||
$('#cronDiv').addClass('layui-hide');
|
||||
$('#simpleDiv').removeClass('layui-hide');
|
||||
}
|
||||
});
|
||||
|
||||
// 初始查询
|
||||
search();
|
||||
});
|
||||
|
||||
// 查询
|
||||
function search() {
|
||||
let quartzName = $("#searchName").val();
|
||||
let quartzType = $("#searchType").val();
|
||||
|
||||
table.reload('quartzTable', {
|
||||
method: 'get',
|
||||
url: '/quartzConfig/findQuartzConfig',
|
||||
where: {
|
||||
quartz_name: quartzName,
|
||||
quartz_type: quartzType
|
||||
},
|
||||
page: {
|
||||
curr: 1
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 编辑任务
|
||||
function editQuartz(data) {
|
||||
isEditMode = true;
|
||||
|
||||
form.val('quartzForm', {
|
||||
configId: data.id,
|
||||
quartzName: data.quartzName,
|
||||
jobType: data.quartzType,
|
||||
quartz_class: data.quartzClass,
|
||||
cronExpression: data.expression,
|
||||
remark: data.remark
|
||||
});
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: "编辑定时任务",
|
||||
shade: 0.3,
|
||||
area: ['600px', '90%'],
|
||||
offset: 'auto',
|
||||
content: $("#addQuartz"),
|
||||
btn: ['保存', '取消'],
|
||||
btnAlign: 'c',
|
||||
success: function () {
|
||||
form.render();
|
||||
},
|
||||
yes: function (index, layero) {
|
||||
saveQuartz(index);
|
||||
},
|
||||
btn2: function () {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 保存任务
|
||||
function saveQuartz(index) {
|
||||
let quartzName = $("#quartzName").val();
|
||||
let jobType = $("#jobType").val();
|
||||
let quartzClass = $("#quartz_class").val();
|
||||
let remark = $("#remark").val();
|
||||
let configId = $("#configId").val();
|
||||
|
||||
if (!quartzName) {
|
||||
layer.msg('请输入任务名称', {icon: 2});
|
||||
return;
|
||||
}
|
||||
if (!jobType) {
|
||||
layer.msg('请选择任务类型', {icon: 2});
|
||||
return;
|
||||
}
|
||||
if (!quartzClass) {
|
||||
layer.msg('请输入任务类', {icon: 2});
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取cron表达式
|
||||
let timeType = $("input[name='timeType']:checked").val();
|
||||
let cronExpression = '';
|
||||
|
||||
if (timeType === 'cron') {
|
||||
cronExpression = $("#cronExpression").val();
|
||||
if (!cronExpression) {
|
||||
layer.msg('请输入Cron表达式', {icon: 2});
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// 简单配置转换为cron表达式
|
||||
let intervalValue = $("#intervalValue").val();
|
||||
let intervalUnit = $("#intervalUnit").val();
|
||||
|
||||
if (intervalUnit === 'hour') {
|
||||
cronExpression = '0 0 0/' + intervalValue + ' * * ?';
|
||||
} else if (intervalUnit === 'day') {
|
||||
cronExpression = '0 0 2 */' + intervalValue + ' * ?';
|
||||
} else if (intervalUnit === 'week') {
|
||||
cronExpression = '0 0 2 ? * MON/' + intervalValue;
|
||||
}
|
||||
}
|
||||
|
||||
let url = isEditMode ? '/quartzConfig/modifyQuartz' : '/quartzConfig/addNewQuartz';
|
||||
let param = {
|
||||
quartzName: quartzName,
|
||||
jobType: jobType,
|
||||
quartz_class: quartzClass,
|
||||
time: cronExpression,
|
||||
remark: remark
|
||||
};
|
||||
|
||||
if (isEditMode) {
|
||||
param.configId = configId;
|
||||
}
|
||||
|
||||
let load = layer.load();
|
||||
AjaxPostJson(url, param, function (data) {
|
||||
layer.close(load);
|
||||
if (data.errCode === "0") {
|
||||
layer.msg('保存成功', {icon: 1, time: 1000}, function () {
|
||||
layer.close(index);
|
||||
search();
|
||||
});
|
||||
} else {
|
||||
layer.alert(data.errMsg || '保存失败', {icon: 2});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 修改状态
|
||||
function changeStatus(configId, status) {
|
||||
let statusText = status === '1' ? '启动' : '暂停';
|
||||
|
||||
layer.confirm('确定要' + statusText + '该任务吗?', {title: statusText + '任务'}, function (index) {
|
||||
let url = '/quartzConfig/changestatus';
|
||||
let param = {
|
||||
configId: configId,
|
||||
status: status
|
||||
};
|
||||
|
||||
let load = layer.load();
|
||||
AjaxPostJson(url, param, function (data) {
|
||||
layer.close(load);
|
||||
layer.close(index);
|
||||
|
||||
if (data.errCode === "0") {
|
||||
layer.msg(statusText + '成功', {icon: 1, time: 1000}, function () {
|
||||
search();
|
||||
});
|
||||
} else {
|
||||
layer.alert(data.errMsg || statusText + '失败', {icon: 2});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 删除任务
|
||||
function deleteQuartz(configId) {
|
||||
layer.confirm('确定删除该定时任务吗?删除后将无法恢复!', {title: '删除任务'}, function (index) {
|
||||
let url = '/quartzConfig/deleteQuartz';
|
||||
let param = {
|
||||
configId: configId
|
||||
};
|
||||
|
||||
let load = layer.load();
|
||||
AjaxPostJson(url, param, function (data) {
|
||||
layer.close(load);
|
||||
layer.close(index);
|
||||
|
||||
if (data.errCode === "0") {
|
||||
layer.msg('删除成功', {icon: 1, time: 1000}, function () {
|
||||
search();
|
||||
});
|
||||
} else {
|
||||
layer.alert(data.errMsg || '删除失败', {icon: 2});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 刷新任务列表
|
||||
function refreshJobList() {
|
||||
let load = layer.load(1, {shade: [0.3, '#000']});
|
||||
|
||||
$.ajax({
|
||||
url: '/quartzConfig/get_all_jobs',
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
success: function (data) {
|
||||
layer.close(load);
|
||||
if (data.quartzJobsVOList) {
|
||||
layer.msg('刷新成功,当前运行中的任务数:' + data.quartzJobsVOList.length, {icon: 1});
|
||||
search();
|
||||
} else {
|
||||
layer.msg('刷新成功', {icon: 1});
|
||||
search();
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
layer.close(load);
|
||||
layer.alert('刷新失败,请检查网络连接!', {icon: 2});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 显示Cron帮助
|
||||
function showCronHelp() {
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: 'Cron表达式帮助',
|
||||
shade: 0.3,
|
||||
area: ['600px', '500px'],
|
||||
content: $("#cronHelp")
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user