门诊号码管理维护界面前后端
This commit is contained in:
@@ -0,0 +1,219 @@
|
|||||||
|
package com.openhis.web.basicmanage.controller;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.core.common.annotation.Log;
|
||||||
|
import com.core.common.core.domain.R;
|
||||||
|
import com.core.common.enums.BusinessType;
|
||||||
|
import com.core.common.utils.SecurityUtils;
|
||||||
|
import com.core.common.utils.StringUtils;
|
||||||
|
import com.openhis.administration.domain.OutpatientNoSegment;
|
||||||
|
import com.openhis.administration.service.IOutpatientNoSegmentService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 门诊号码段管理控制器
|
||||||
|
*
|
||||||
|
* @author system
|
||||||
|
* @date 2025-01-XX
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/business-rule/outpatient-no")
|
||||||
|
public class OutpatientNoSegmentController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IOutpatientNoSegmentService outpatientNoSegmentService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询门诊号码段列表
|
||||||
|
*
|
||||||
|
* @param pageNo 页码
|
||||||
|
* @param pageSize 每页条数
|
||||||
|
* @param onlySelf 是否只查询自己的(true=只查询自己的,false=查询所有)
|
||||||
|
* @return 门诊号码段列表
|
||||||
|
*/
|
||||||
|
@GetMapping("/page")
|
||||||
|
public R<?> selectOutpatientNoSegmentPage(
|
||||||
|
@RequestParam(defaultValue = "1") Integer pageNo,
|
||||||
|
@RequestParam(defaultValue = "10") Integer pageSize,
|
||||||
|
@RequestParam(required = false) Boolean onlySelf) {
|
||||||
|
|
||||||
|
// 获取当前用户ID
|
||||||
|
Long userId = SecurityUtils.getUserId();
|
||||||
|
|
||||||
|
// 如果onlySelf为null,默认只查询自己的
|
||||||
|
boolean onlySelfFlag = onlySelf != null ? onlySelf : true;
|
||||||
|
|
||||||
|
// 分页查询门诊号码段列表
|
||||||
|
Page<OutpatientNoSegment> page = new Page<>(pageNo, pageSize);
|
||||||
|
Page<OutpatientNoSegment> result = outpatientNoSegmentService.selectOutpatientNoSegmentPage(page, onlySelfFlag, userId);
|
||||||
|
|
||||||
|
return R.ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增门诊号码段
|
||||||
|
*
|
||||||
|
* @param outpatientNoSegment 门诊号码段信息
|
||||||
|
* @return 操作结果
|
||||||
|
*/
|
||||||
|
@Log(title = "门诊号码管理", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping
|
||||||
|
public R<?> addOutpatientNoSegment(@RequestBody OutpatientNoSegment outpatientNoSegment) {
|
||||||
|
// 校验必填字段
|
||||||
|
if (StringUtils.isEmpty(outpatientNoSegment.getStartNo()) ||
|
||||||
|
StringUtils.isEmpty(outpatientNoSegment.getEndNo()) ||
|
||||||
|
StringUtils.isEmpty(outpatientNoSegment.getUsedNo())) {
|
||||||
|
return R.fail("起始号码、终止号码和使用号码不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 校验号码段是否重复
|
||||||
|
if (outpatientNoSegmentService.checkNumberSegmentOverlap(
|
||||||
|
outpatientNoSegment.getStartNo(),
|
||||||
|
outpatientNoSegment.getEndNo(),
|
||||||
|
null)) {
|
||||||
|
return R.fail("门诊号码设置重复");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置创建人信息
|
||||||
|
outpatientNoSegment.setOperatorId(SecurityUtils.getUserId());
|
||||||
|
if (StringUtils.isEmpty(outpatientNoSegment.getOperatorName())) {
|
||||||
|
outpatientNoSegment.setOperatorName(SecurityUtils.getUsername());
|
||||||
|
}
|
||||||
|
outpatientNoSegment.setCreateBy(SecurityUtils.getUsername());
|
||||||
|
|
||||||
|
int result = outpatientNoSegmentService.insertOutpatientNoSegment(outpatientNoSegment);
|
||||||
|
return result > 0 ? R.ok("保存成功") : R.fail("保存失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改门诊号码段
|
||||||
|
*
|
||||||
|
* @param outpatientNoSegment 门诊号码段信息
|
||||||
|
* @return 操作结果
|
||||||
|
*/
|
||||||
|
@Log(title = "门诊号码管理", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping
|
||||||
|
public R<?> updateOutpatientNoSegment(@RequestBody OutpatientNoSegment outpatientNoSegment) {
|
||||||
|
// 校验必填字段
|
||||||
|
if (StringUtils.isEmpty(outpatientNoSegment.getStartNo()) ||
|
||||||
|
StringUtils.isEmpty(outpatientNoSegment.getEndNo()) ||
|
||||||
|
StringUtils.isEmpty(outpatientNoSegment.getUsedNo())) {
|
||||||
|
return R.fail("起始号码、终止号码和使用号码不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 校验号码段是否重复(排除自身)
|
||||||
|
if (outpatientNoSegmentService.checkNumberSegmentOverlap(
|
||||||
|
outpatientNoSegment.getStartNo(),
|
||||||
|
outpatientNoSegment.getEndNo(),
|
||||||
|
outpatientNoSegment.getId())) {
|
||||||
|
return R.fail("门诊号码设置重复");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置更新人信息
|
||||||
|
outpatientNoSegment.setUpdateBy(SecurityUtils.getUsername());
|
||||||
|
|
||||||
|
int result = outpatientNoSegmentService.updateOutpatientNoSegment(outpatientNoSegment);
|
||||||
|
return result > 0 ? R.ok("保存成功") : R.fail("保存失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除门诊号码段
|
||||||
|
*
|
||||||
|
* @param request 包含ids数组的请求对象
|
||||||
|
* @return 操作结果
|
||||||
|
*/
|
||||||
|
@Log(title = "门诊号码管理", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping
|
||||||
|
public R<?> deleteOutpatientNoSegment(@RequestBody java.util.Map<String, Object> request) {
|
||||||
|
// 支持接收 Long[] 或 String[] 或混合类型,处理大整数ID
|
||||||
|
Object idsObj = request.get("ids");
|
||||||
|
System.out.println("删除请求 - 接收到的ids原始数据: " + idsObj);
|
||||||
|
System.out.println("删除请求 - 接收到的ids类型: " + (idsObj != null ? idsObj.getClass().getName() : "null"));
|
||||||
|
|
||||||
|
if (idsObj == null) {
|
||||||
|
return R.fail("请选择要删除的数据");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换为 Long[] 数组
|
||||||
|
Long[] ids = null;
|
||||||
|
if (idsObj instanceof java.util.List) {
|
||||||
|
java.util.List<?> idList = (java.util.List<?>) idsObj;
|
||||||
|
ids = new Long[idList.size()];
|
||||||
|
for (int i = 0; i < idList.size(); i++) {
|
||||||
|
Object idObj = idList.get(i);
|
||||||
|
if (idObj instanceof Long) {
|
||||||
|
ids[i] = (Long) idObj;
|
||||||
|
} else if (idObj instanceof Integer) {
|
||||||
|
ids[i] = ((Integer) idObj).longValue();
|
||||||
|
} else if (idObj instanceof String) {
|
||||||
|
try {
|
||||||
|
String idStr = (String) idObj;
|
||||||
|
System.out.println("删除请求 - 转换字符串ID: " + idStr);
|
||||||
|
ids[i] = Long.parseLong(idStr);
|
||||||
|
System.out.println("删除请求 - 转换后的Long ID: " + ids[i]);
|
||||||
|
// 验证转换是否正确
|
||||||
|
if (!String.valueOf(ids[i]).equals(idStr)) {
|
||||||
|
System.out.println("删除请求 - 警告:ID转换后值不匹配!原始: " + idStr + ", 转换后: " + ids[i]);
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
System.out.println("删除请求 - ID转换失败: " + idObj + ", 错误: " + e.getMessage());
|
||||||
|
return R.fail("无效的ID格式: " + idObj);
|
||||||
|
}
|
||||||
|
} else if (idObj instanceof Number) {
|
||||||
|
ids[i] = ((Number) idObj).longValue();
|
||||||
|
} else {
|
||||||
|
return R.fail("无效的ID类型: " + (idObj != null ? idObj.getClass().getName() : "null"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (idsObj instanceof Long[]) {
|
||||||
|
ids = (Long[]) idsObj;
|
||||||
|
} else {
|
||||||
|
return R.fail("无效的ID数组格式");
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("删除请求 - 转换后的ids: " + java.util.Arrays.toString(ids));
|
||||||
|
|
||||||
|
if (ids == null || ids.length == 0) {
|
||||||
|
return R.fail("请选择要删除的数据");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前用户ID
|
||||||
|
Long userId = SecurityUtils.getUserId();
|
||||||
|
System.out.println("删除请求 - 当前用户ID: " + userId);
|
||||||
|
|
||||||
|
// 校验删除权限和使用状态
|
||||||
|
for (Long id : ids) {
|
||||||
|
System.out.println("删除验证 - 检查ID: " + id);
|
||||||
|
OutpatientNoSegment segment = outpatientNoSegmentService.getById(id);
|
||||||
|
|
||||||
|
if (segment == null) {
|
||||||
|
// 记录日志以便调试
|
||||||
|
System.out.println("删除失败:记录不存在,ID=" + id + ",可能已被软删除或不存在");
|
||||||
|
return R.fail("数据不存在,ID: " + id);
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("删除验证 - 找到记录: ID=" + segment.getId() + ", operatorId=" + segment.getOperatorId() + ", usedNo=" + segment.getUsedNo() + ", startNo=" + segment.getStartNo());
|
||||||
|
|
||||||
|
// 校验归属权
|
||||||
|
if (!segment.getOperatorId().equals(userId)) {
|
||||||
|
System.out.println("删除验证 - 权限检查失败: segment.operatorId=" + segment.getOperatorId() + ", userId=" + userId);
|
||||||
|
return R.fail("只能删除自己维护的门诊号码段");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 校验使用状态(使用号码=起始号码表示未使用)
|
||||||
|
if (!segment.getUsedNo().equals(segment.getStartNo())) {
|
||||||
|
System.out.println("删除验证 - 使用状态检查失败: usedNo=" + segment.getUsedNo() + ", startNo=" + segment.getStartNo());
|
||||||
|
return R.fail("已有门诊号码段已有使用的门诊号码,请核对!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("删除验证 - 所有检查通过,开始执行删除");
|
||||||
|
int rows = outpatientNoSegmentService.deleteOutpatientNoSegmentByIds(ids);
|
||||||
|
System.out.println("删除执行 - 影响行数: " + rows);
|
||||||
|
return rows > 0 ? R.ok("删除成功") : R.fail("删除失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package com.openhis.administration.domain;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||||
|
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||||
|
|
||||||
|
import com.core.common.core.domain.HisBaseEntity;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 门诊号码段管理Entity实体
|
||||||
|
*
|
||||||
|
* @author system
|
||||||
|
* @date 2025-01-XX
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@TableName("adm_outpatient_no_segment")
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
public class OutpatientNoSegment extends HisBaseEntity {
|
||||||
|
|
||||||
|
/** ID */
|
||||||
|
@TableId(type = IdType.ASSIGN_ID)
|
||||||
|
@JsonSerialize(using = ToStringSerializer.class)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/** 操作员ID */
|
||||||
|
private Long operatorId;
|
||||||
|
|
||||||
|
/** 操作员姓名 */
|
||||||
|
private String operatorName;
|
||||||
|
|
||||||
|
/** 员工工号 */
|
||||||
|
private String staffNo;
|
||||||
|
|
||||||
|
/** 领用日期 */
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||||
|
private Date receiveDate;
|
||||||
|
|
||||||
|
/** 起始号码 */
|
||||||
|
private String startNo;
|
||||||
|
|
||||||
|
/** 终止号码 */
|
||||||
|
private String endNo;
|
||||||
|
|
||||||
|
/** 使用号码 */
|
||||||
|
private String usedNo;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package com.openhis.administration.mapper;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.openhis.administration.domain.OutpatientNoSegment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 门诊号码段管理Mapper接口
|
||||||
|
*
|
||||||
|
* @author system
|
||||||
|
* @date 2025-01-XX
|
||||||
|
*/
|
||||||
|
@Repository
|
||||||
|
public interface OutpatientNoSegmentMapper extends BaseMapper<OutpatientNoSegment> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
package com.openhis.administration.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.openhis.administration.domain.OutpatientNoSegment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 门诊号码段管理Service接口
|
||||||
|
*
|
||||||
|
* @author system
|
||||||
|
* @date 2025-01-XX
|
||||||
|
*/
|
||||||
|
public interface IOutpatientNoSegmentService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询门诊号码段列表
|
||||||
|
*
|
||||||
|
* @param page 分页对象
|
||||||
|
* @param onlySelf 是否只查询自己的(true=只查询自己的,false=查询所有)
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @return 分页结果
|
||||||
|
*/
|
||||||
|
Page<OutpatientNoSegment> selectOutpatientNoSegmentPage(Page<OutpatientNoSegment> page, boolean onlySelf, Long userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增门诊号码段
|
||||||
|
*
|
||||||
|
* @param outpatientNoSegment 门诊号码段信息
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int insertOutpatientNoSegment(OutpatientNoSegment outpatientNoSegment);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改门诊号码段
|
||||||
|
*
|
||||||
|
* @param outpatientNoSegment 门诊号码段信息
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int updateOutpatientNoSegment(OutpatientNoSegment outpatientNoSegment);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除门诊号码段
|
||||||
|
*
|
||||||
|
* @param ids 门诊号码段ID列表
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int deleteOutpatientNoSegmentByIds(Long[] ids);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据ID查询门诊号码段
|
||||||
|
*
|
||||||
|
* @param id 门诊号码段ID
|
||||||
|
* @return 门诊号码段信息
|
||||||
|
*/
|
||||||
|
OutpatientNoSegment getById(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查号码段是否重复(全系统范围)
|
||||||
|
*
|
||||||
|
* @param startNo 起始号码
|
||||||
|
* @param endNo 终止号码
|
||||||
|
* @param excludeId 排除的ID(用于更新时排除自身)
|
||||||
|
* @return true=重复,false=不重复
|
||||||
|
*/
|
||||||
|
boolean checkNumberSegmentOverlap(String startNo, String endNo, Long excludeId);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,241 @@
|
|||||||
|
package com.openhis.administration.service.impl;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import com.openhis.administration.domain.OutpatientNoSegment;
|
||||||
|
import com.openhis.administration.mapper.OutpatientNoSegmentMapper;
|
||||||
|
import com.openhis.administration.service.IOutpatientNoSegmentService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 门诊号码段管理Service实现
|
||||||
|
*
|
||||||
|
* @author system
|
||||||
|
* @date 2025-01-XX
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class OutpatientNoSegmentServiceImpl implements IOutpatientNoSegmentService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private OutpatientNoSegmentMapper outpatientNoSegmentMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询门诊号码段列表
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Page<OutpatientNoSegment> selectOutpatientNoSegmentPage(Page<OutpatientNoSegment> page, boolean onlySelf, Long userId) {
|
||||||
|
LambdaQueryWrapper<OutpatientNoSegment> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
|
||||||
|
// 如果不是管理员,只查询自己的号码段
|
||||||
|
if (onlySelf && userId != null) {
|
||||||
|
queryWrapper.eq(OutpatientNoSegment::getOperatorId, userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按创建时间正序排列(新记录排在后面)
|
||||||
|
queryWrapper.orderByAsc(OutpatientNoSegment::getCreateTime);
|
||||||
|
|
||||||
|
return outpatientNoSegmentMapper.selectPage(page, queryWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增门诊号码段
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int insertOutpatientNoSegment(OutpatientNoSegment outpatientNoSegment) {
|
||||||
|
return outpatientNoSegmentMapper.insert(outpatientNoSegment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改门诊号码段
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int updateOutpatientNoSegment(OutpatientNoSegment outpatientNoSegment) {
|
||||||
|
return outpatientNoSegmentMapper.updateById(outpatientNoSegment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除门诊号码段
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int deleteOutpatientNoSegmentByIds(Long[] ids) {
|
||||||
|
if (ids == null || ids.length == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return outpatientNoSegmentMapper.deleteBatchIds(java.util.Arrays.asList(ids));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据ID查询门诊号码段
|
||||||
|
* 注意:由于 @TableLogic 注解,selectById 会自动过滤已删除的记录(delete_flag = '1')
|
||||||
|
* 这意味着如果记录已经被软删除,此方法会返回 null
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public OutpatientNoSegment getById(Long id) {
|
||||||
|
System.out.println("=== 查询门诊号码段开始 ===");
|
||||||
|
System.out.println("查询ID: " + id);
|
||||||
|
System.out.println("ID类型: " + (id != null ? id.getClass().getName() : "null"));
|
||||||
|
System.out.println("ID值(字符串): " + String.valueOf(id));
|
||||||
|
|
||||||
|
// 使用 selectById 查询(会自动过滤 delete_flag = '1' 的记录)
|
||||||
|
OutpatientNoSegment segment = outpatientNoSegmentMapper.selectById(id);
|
||||||
|
|
||||||
|
if (segment != null) {
|
||||||
|
System.out.println("查询成功 - 找到记录:");
|
||||||
|
System.out.println(" - 记录ID: " + segment.getId());
|
||||||
|
System.out.println(" - 操作员ID: " + segment.getOperatorId());
|
||||||
|
System.out.println(" - 起始号码: " + segment.getStartNo());
|
||||||
|
System.out.println(" - 终止号码: " + segment.getEndNo());
|
||||||
|
System.out.println(" - 使用号码: " + segment.getUsedNo());
|
||||||
|
} else {
|
||||||
|
System.out.println("查询失败 - 未找到记录");
|
||||||
|
System.out.println("可能原因:");
|
||||||
|
System.out.println(" 1. 记录不存在");
|
||||||
|
System.out.println(" 2. 记录已被软删除(delete_flag = '1')");
|
||||||
|
System.out.println(" 3. ID 不匹配");
|
||||||
|
|
||||||
|
// 尝试直接查询数据库(包括已删除的记录)来验证记录是否存在
|
||||||
|
try {
|
||||||
|
LambdaQueryWrapper<OutpatientNoSegment> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
queryWrapper.eq(OutpatientNoSegment::getId, id);
|
||||||
|
// 注意:这里仍然会受到 @TableLogic 的影响,无法查询已删除的记录
|
||||||
|
// 如果需要查询已删除的记录,需要使用原生 SQL 或禁用逻辑删除
|
||||||
|
OutpatientNoSegment segmentWithDeleted = outpatientNoSegmentMapper.selectOne(queryWrapper);
|
||||||
|
if (segmentWithDeleted != null) {
|
||||||
|
System.out.println("使用 LambdaQueryWrapper 查询结果: 找到记录,ID=" + segmentWithDeleted.getId());
|
||||||
|
} else {
|
||||||
|
System.out.println("使用 LambdaQueryWrapper 查询结果: 未找到记录");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println("使用 LambdaQueryWrapper 查询时出错: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试查询所有记录(不限制 delete_flag)来验证 ID 是否存在
|
||||||
|
// 注意:由于 @TableLogic,无法直接查询已删除的记录
|
||||||
|
// 但我们可以查询所有未删除的记录,看看是否有类似的 ID
|
||||||
|
try {
|
||||||
|
LambdaQueryWrapper<OutpatientNoSegment> allQuery = new LambdaQueryWrapper<>();
|
||||||
|
// 查询所有未删除的记录
|
||||||
|
List<OutpatientNoSegment> allSegments = outpatientNoSegmentMapper.selectList(allQuery);
|
||||||
|
System.out.println("数据库中所有未删除的记录数: " + allSegments.size());
|
||||||
|
System.out.println("所有记录的 ID 列表:");
|
||||||
|
for (OutpatientNoSegment seg : allSegments) {
|
||||||
|
System.out.println(" - ID: " + seg.getId() + " (类型: " + seg.getId().getClass().getName() + ")");
|
||||||
|
// 检查是否有接近的 ID(可能是精度问题)
|
||||||
|
if (seg.getId() != null) {
|
||||||
|
String segIdStr = String.valueOf(seg.getId());
|
||||||
|
String searchIdStr = String.valueOf(id);
|
||||||
|
if (segIdStr.length() == searchIdStr.length() &&
|
||||||
|
segIdStr.substring(0, Math.min(10, segIdStr.length())).equals(
|
||||||
|
searchIdStr.substring(0, Math.min(10, searchIdStr.length())))) {
|
||||||
|
System.out.println(" 警告:发现相似的 ID!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println("查询所有记录时出错: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("=== 查询门诊号码段结束 ===");
|
||||||
|
return segment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查号码段是否重复(全系统范围)
|
||||||
|
* 规则:从末位往前找到第一个字母作为前缀,比较前缀和数字范围
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean checkNumberSegmentOverlap(String startNo, String endNo, Long excludeId) {
|
||||||
|
if (startNo == null || endNo == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提取前缀(从末位往前找到第一个字母)
|
||||||
|
String prefix1 = extractPrefix(startNo);
|
||||||
|
String prefix2 = extractPrefix(endNo);
|
||||||
|
|
||||||
|
// 前缀必须一致
|
||||||
|
if (!prefix1.equals(prefix2)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提取尾部数字
|
||||||
|
Long num1 = extractTailNumber(startNo);
|
||||||
|
Long num2 = extractTailNumber(endNo);
|
||||||
|
|
||||||
|
if (num1 == null || num2 == null || num1 > num2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询所有相同前缀的号码段
|
||||||
|
LambdaQueryWrapper<OutpatientNoSegment> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
queryWrapper.likeRight(OutpatientNoSegment::getStartNo, prefix1);
|
||||||
|
if (excludeId != null) {
|
||||||
|
queryWrapper.ne(OutpatientNoSegment::getId, excludeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<OutpatientNoSegment> segments = outpatientNoSegmentMapper.selectList(queryWrapper);
|
||||||
|
|
||||||
|
// 检查是否有重叠
|
||||||
|
for (OutpatientNoSegment segment : segments) {
|
||||||
|
String otherPrefix = extractPrefix(segment.getStartNo());
|
||||||
|
if (!prefix1.equals(otherPrefix)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Long otherNum1 = extractTailNumber(segment.getStartNo());
|
||||||
|
Long otherNum2 = extractTailNumber(segment.getEndNo());
|
||||||
|
|
||||||
|
if (otherNum1 != null && otherNum2 != null) {
|
||||||
|
// 检查范围是否重叠
|
||||||
|
if (Math.max(num1, otherNum1) <= Math.min(num2, otherNum2)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从末位往前找到第一个字母,返回前缀(包含该字母)
|
||||||
|
*/
|
||||||
|
private String extractPrefix(String value) {
|
||||||
|
if (value == null || value.isEmpty()) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
char[] chars = value.toCharArray();
|
||||||
|
for (int i = chars.length - 1; i >= 0; i--) {
|
||||||
|
if (Character.isLetter(chars[i])) {
|
||||||
|
return value.substring(0, i + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提取尾部数字
|
||||||
|
*/
|
||||||
|
private Long extractTailNumber(String value) {
|
||||||
|
if (value == null || value.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Pattern pattern = Pattern.compile("(\\d+)$");
|
||||||
|
Matcher matcher = pattern.matcher(value);
|
||||||
|
if (matcher.find()) {
|
||||||
|
try {
|
||||||
|
return Long.parseLong(matcher.group(1));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -7,19 +7,12 @@ import request from '@/utils/request'
|
|||||||
/**
|
/**
|
||||||
* 分页查询门诊号码段列表
|
* 分页查询门诊号码段列表
|
||||||
* 要求:普通用户只能查看自己的,管理员可以查看所有
|
* 要求:普通用户只能查看自己的,管理员可以查看所有
|
||||||
* 注意:由于后端接口不存在,直接返回失败响应,让调用方使用localStorage数据,避免404错误
|
|
||||||
*/
|
*/
|
||||||
export function listOutpatientNo(query) {
|
export function listOutpatientNo(query) {
|
||||||
// return request({
|
return request({
|
||||||
// url: '/business-rule/outpatient-no/page',
|
url: '/business-rule/outpatient-no/page',
|
||||||
// method: 'get',
|
method: 'get',
|
||||||
// params: query,
|
params: query,
|
||||||
// 由于后端接口不存在,直接返回失败响应(不发送实际请求),避免控制台显示404错误
|
|
||||||
// 调用方会在判断 code !== 200 时使用 localStorage 数据
|
|
||||||
return Promise.resolve({
|
|
||||||
code: 404,
|
|
||||||
msg: '接口不存在,已使用本地数据',
|
|
||||||
data: null
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,11 +43,11 @@ export function updateOutpatientNo(data) {
|
|||||||
* 删除门诊号码段
|
* 删除门诊号码段
|
||||||
*要求:双重校验(归属权+使用状态)
|
*要求:双重校验(归属权+使用状态)
|
||||||
*/
|
*/
|
||||||
export function deleteOutpatientNo(params) {
|
export function deleteOutpatientNo(data) {
|
||||||
return request({
|
return request({
|
||||||
url: '/business-rule/outpatient-no',
|
url: '/business-rule/outpatient-no',
|
||||||
method: 'delete',
|
method: 'delete',
|
||||||
params,
|
data,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
|
||||||
<!-- Windows XP风格窗口布局,600px固定宽度 -->
|
|
||||||
<div class="outpatient-no-management-wrapper">
|
<div class="outpatient-no-management-wrapper">
|
||||||
|
<!-- Windows XP风格窗口布局,全屏显示 -->
|
||||||
<div class="outpatient-no-management">
|
<div class="outpatient-no-management">
|
||||||
<!--标题栏(32px高) -->
|
<!--标题栏(32px高) -->
|
||||||
<div class="title-bar">
|
<div class="title-bar">
|
||||||
@@ -45,62 +44,25 @@
|
|||||||
<el-table-column type="selection" width="50" align="center" />
|
<el-table-column type="selection" width="50" align="center" />
|
||||||
<el-table-column label="序号" type="index" width="60" align="center" />
|
<el-table-column label="序号" type="index" width="60" align="center" />
|
||||||
<el-table-column label="操作员" prop="operatorName" min-width="120" />
|
<el-table-column label="操作员" prop="operatorName" min-width="120" />
|
||||||
<el-table-column label="员工工号" prop="staffNo" min-width="120">
|
<el-table-column label="员工工号" prop="staffNo" min-width="120" />
|
||||||
<template #default="{ row }">
|
|
||||||
<el-input
|
|
||||||
v-if="row._editing"
|
|
||||||
v-model.trim="row.staffNo"
|
|
||||||
/>
|
|
||||||
<span v-else>{{ row.staffNo }}</span>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="领用日期" prop="receiveDate" min-width="140">
|
<el-table-column label="领用日期" prop="receiveDate" min-width="140">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-date-picker
|
{{ formatReceiveDate(row.receiveDate) }}
|
||||||
v-if="row._editing"
|
|
||||||
v-model="row.receiveDate"
|
|
||||||
type="date"
|
|
||||||
value-format="YYYY-MM-DD"
|
|
||||||
placeholder="选择日期"
|
|
||||||
style="width: 100%"
|
|
||||||
/>
|
|
||||||
<span v-else>{{ row.receiveDate }}</span>
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="起始号码" prop="startNo" min-width="140">
|
<el-table-column label="起始号码" prop="startNo" min-width="140" />
|
||||||
|
<el-table-column label="终止号码" prop="endNo" min-width="140" />
|
||||||
|
<el-table-column label="使用号码" prop="usedNo" min-width="140" />
|
||||||
|
<el-table-column label="操作" width="120" align="center" fixed="right">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-input
|
<el-button
|
||||||
v-if="row._editing"
|
type="primary"
|
||||||
v-model.trim="row.startNo"
|
link
|
||||||
@input="() => onStartNoChange(row)"
|
size="small"
|
||||||
@blur="() => validateNumField(row, 'startNo')"
|
@click="handleEdit(row)"
|
||||||
/>
|
>
|
||||||
<span v-else>{{ row.startNo }}</span>
|
编辑
|
||||||
</template>
|
</el-button>
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="终止号码" prop="endNo" min-width="140">
|
|
||||||
<template #default="{ row }">
|
|
||||||
<el-input
|
|
||||||
v-if="row._editing"
|
|
||||||
v-model.trim="row.endNo"
|
|
||||||
@blur="() => validateNumField(row, 'endNo')"
|
|
||||||
/>
|
|
||||||
<span v-else>{{ row.endNo }}</span>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="使用号码" prop="usedNo" min-width="140">
|
|
||||||
<template #default="{ row }">
|
|
||||||
<el-input
|
|
||||||
v-if="row._editing"
|
|
||||||
v-model.trim="row.usedNo"
|
|
||||||
@blur="() => validateNumField(row, 'usedNo')"
|
|
||||||
/>
|
|
||||||
<span v-else>{{ row.usedNo }}</span>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="操作" width="100" fixed="right">
|
|
||||||
<template #default="scope">
|
|
||||||
<el-button type="primary" link icon="Edit" @click="() => openEdit(scope.row, scope.$index)">编辑</el-button>
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@@ -113,41 +75,65 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 编辑弹窗 -->
|
<!-- 编辑弹窗 -->
|
||||||
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="600px" append-to-body>
|
<el-dialog
|
||||||
<el-form label-width="100px">
|
v-model="editDialogVisible"
|
||||||
<el-form-item label="操作员">
|
title="编辑门诊号码段"
|
||||||
|
width="600px"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
>
|
||||||
|
<el-form
|
||||||
|
ref="editFormRef"
|
||||||
|
:model="editForm"
|
||||||
|
:rules="editFormRules"
|
||||||
|
label-width="120px"
|
||||||
|
>
|
||||||
|
<el-form-item label="操作员" prop="operatorName">
|
||||||
<el-input v-model="editForm.operatorName" disabled />
|
<el-input v-model="editForm.operatorName" disabled />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="员工工号">
|
<el-form-item label="员工工号" prop="staffNo">
|
||||||
<el-input v-model.trim="editForm.staffNo" />
|
<el-input v-model.trim="editForm.staffNo" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="领用日期">
|
<el-form-item label="领用日期" prop="receiveDate">
|
||||||
<el-date-picker v-model="editForm.receiveDate" type="date" value-format="YYYY-MM-DD" style="width: 100%" />
|
<el-date-picker
|
||||||
|
v-model="editForm.receiveDate"
|
||||||
|
type="date"
|
||||||
|
value-format="YYYY.MM.DD"
|
||||||
|
placeholder="选择日期"
|
||||||
|
style="width: 100%"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="起始号码">
|
<el-form-item label="起始号码" prop="startNo">
|
||||||
<el-input v-model.trim="editForm.startNo" @blur="() => validateNumField(editForm, 'startNo')" />
|
<el-input
|
||||||
|
v-model.trim="editForm.startNo"
|
||||||
|
@input="onEditFormStartNoChange"
|
||||||
|
@blur="validateEditFormField('startNo')"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="终止号码">
|
<el-form-item label="终止号码" prop="endNo">
|
||||||
<el-input v-model.trim="editForm.endNo" @blur="() => validateNumField(editForm, 'endNo')" />
|
<el-input
|
||||||
|
v-model.trim="editForm.endNo"
|
||||||
|
@blur="validateEditFormField('endNo')"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="使用号码">
|
<el-form-item label="使用号码" prop="usedNo">
|
||||||
<el-input v-model.trim="editForm.usedNo" @blur="() => validateNumField(editForm, 'usedNo')" />
|
<el-input
|
||||||
|
v-model.trim="editForm.usedNo"
|
||||||
|
@blur="validateEditFormField('usedNo')"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div class="dialog-footer">
|
<el-button @click="editDialogVisible = false">取消</el-button>
|
||||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
<el-button type="primary" @click="handleSaveEditForm">保存</el-button>
|
||||||
<el-button type="primary" @click="confirmEdit">确 定</el-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup name="outpatientNoManagement">
|
<script setup name="outpatientNoManagement">
|
||||||
|
import { ref, reactive, toRefs, onActivated, getCurrentInstance } from 'vue'
|
||||||
import useUserStore from '@/store/modules/user'
|
import useUserStore from '@/store/modules/user'
|
||||||
import { getConfigKey } from '@/api/system/config'
|
import { getConfigKey } from '@/api/system/config'
|
||||||
import { logQuery, logCreate, logUpdate, logDelete } from './components/operationLog'
|
import { logQuery, logCreate, logUpdate, logDelete } from './components/operationLog'
|
||||||
@@ -162,6 +148,34 @@ const getUserInfo = () => ({
|
|||||||
name: userStore.name || userStore.nickName
|
name: userStore.name || userStore.nickName
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 格式化领用日期为 YYYY.MM.DD 格式(用于显示)
|
||||||
|
function formatReceiveDate(dateStr) {
|
||||||
|
if (!dateStr) return ''
|
||||||
|
// 如果是 YYYY-MM-DD 格式,转换为 YYYY.MM.DD
|
||||||
|
if (dateStr.includes('-')) {
|
||||||
|
return dateStr.replace(/-/g, '.')
|
||||||
|
}
|
||||||
|
// 如果已经是 YYYY.MM.DD 格式,直接返回
|
||||||
|
if (dateStr.includes('.')) {
|
||||||
|
return dateStr
|
||||||
|
}
|
||||||
|
return dateStr
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将日期格式从 YYYY.MM.DD 转换为 yyyy-MM-dd(用于发送到后端)
|
||||||
|
function convertDateForBackend(dateStr) {
|
||||||
|
if (!dateStr) return null
|
||||||
|
// 如果是 YYYY.MM.DD 格式,转换为 yyyy-MM-dd
|
||||||
|
if (dateStr.includes('.')) {
|
||||||
|
return dateStr.replace(/\./g, '-')
|
||||||
|
}
|
||||||
|
// 如果已经是 yyyy-MM-dd 格式,直接返回
|
||||||
|
if (dateStr.includes('-')) {
|
||||||
|
return dateStr
|
||||||
|
}
|
||||||
|
return dateStr
|
||||||
|
}
|
||||||
|
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const tableData = ref([])
|
const tableData = ref([])
|
||||||
const total = ref(0)
|
const total = ref(0)
|
||||||
@@ -169,18 +183,31 @@ const ids = ref([])
|
|||||||
const multiple = ref(true)
|
const multiple = ref(true)
|
||||||
const viewAll = ref(false)
|
const viewAll = ref(false)
|
||||||
const canToggleViewAll = ref(false)
|
const canToggleViewAll = ref(false)
|
||||||
const dialogVisible = ref(false)
|
|
||||||
const dialogTitle = ref('编辑门诊号码段')
|
// 编辑弹窗相关
|
||||||
const editIndex = ref(-1)
|
const editDialogVisible = ref(false)
|
||||||
|
const editFormRef = ref(null)
|
||||||
const editForm = reactive({
|
const editForm = reactive({
|
||||||
|
id: null,
|
||||||
|
operatorId: null,
|
||||||
|
operatorName: '',
|
||||||
|
staffNo: '',
|
||||||
receiveDate: '',
|
receiveDate: '',
|
||||||
startNo: '',
|
startNo: '',
|
||||||
endNo: '',
|
endNo: '',
|
||||||
usedNo: '',
|
usedNo: '',
|
||||||
operatorName: '',
|
_originalData: null,
|
||||||
staffNo: '',
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 编辑表单验证规则
|
||||||
|
const editFormRules = {
|
||||||
|
staffNo: [{ required: true, message: '请输入员工工号', trigger: 'blur' }],
|
||||||
|
receiveDate: [{ required: true, message: '请选择领用日期', trigger: 'change' }],
|
||||||
|
startNo: [{ required: true, message: '请输入起始号码', trigger: 'blur' }],
|
||||||
|
endNo: [{ required: true, message: '请输入终止号码', trigger: 'blur' }],
|
||||||
|
usedNo: [{ required: true, message: '请输入使用号码', trigger: 'blur' }],
|
||||||
|
}
|
||||||
|
|
||||||
const data = reactive({
|
const data = reactive({
|
||||||
queryParams: {
|
queryParams: {
|
||||||
pageNo: 1,
|
pageNo: 1,
|
||||||
@@ -218,18 +245,146 @@ function onAdd() {
|
|||||||
const yyyy = now.getFullYear()
|
const yyyy = now.getFullYear()
|
||||||
const mm = String(now.getMonth() + 1).padStart(2, '0')
|
const mm = String(now.getMonth() + 1).padStart(2, '0')
|
||||||
const dd = String(now.getDate()).padStart(2, '0')
|
const dd = String(now.getDate()).padStart(2, '0')
|
||||||
tableData.value.push({
|
|
||||||
id: undefined,
|
// 打开编辑弹窗,用于新增
|
||||||
operatorId: userStore.id,
|
editForm.id = undefined
|
||||||
operatorName: userStore.name || userStore.nickName,
|
editForm.operatorId = userStore.id
|
||||||
staffNo: userStore.id,
|
editForm.operatorName = userStore.name || userStore.nickName
|
||||||
receiveDate: `${yyyy}-${mm}-${dd}`,
|
editForm.staffNo = userStore.id
|
||||||
startNo: '',
|
editForm.receiveDate = `${yyyy}.${mm}.${dd}`
|
||||||
endNo: '',
|
editForm.startNo = ''
|
||||||
usedNo: '',
|
editForm.endNo = ''
|
||||||
_editing: true,
|
editForm.usedNo = ''
|
||||||
_error: false,
|
editForm._originalData = null
|
||||||
})
|
editDialogVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 编辑行 - 打开编辑弹窗
|
||||||
|
function handleEdit(row) {
|
||||||
|
// 复制行数据到编辑表单
|
||||||
|
editForm.id = row.id
|
||||||
|
editForm.operatorId = row.operatorId
|
||||||
|
editForm.operatorName = row.operatorName
|
||||||
|
editForm.staffNo = row.staffNo
|
||||||
|
editForm.receiveDate = formatReceiveDate(row.receiveDate)
|
||||||
|
editForm.startNo = row.startNo
|
||||||
|
editForm.endNo = row.endNo
|
||||||
|
editForm.usedNo = row.usedNo
|
||||||
|
editForm._originalData = { ...row }
|
||||||
|
editDialogVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 编辑表单中起始号码变化时自动设置使用号码
|
||||||
|
function onEditFormStartNoChange() {
|
||||||
|
if (!editForm.id && editForm.startNo) {
|
||||||
|
editForm.usedNo = editForm.startNo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证编辑表单字段
|
||||||
|
function validateEditFormField(field) {
|
||||||
|
if (!isTailDigitsValid(editForm[field])) {
|
||||||
|
const msg = `最大位数为12位,且必须以数字结尾!`
|
||||||
|
alertWarn(msg)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存编辑表单
|
||||||
|
async function handleSaveEditForm() {
|
||||||
|
// 表单验证
|
||||||
|
if (!editFormRef.value) return
|
||||||
|
try {
|
||||||
|
const valid = await editFormRef.value.validate()
|
||||||
|
if (!valid) return
|
||||||
|
} catch (error) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 字段验证
|
||||||
|
if (!validateEditFormField('startNo') || !validateEditFormField('endNo') || !validateEditFormField('usedNo')) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建验证用的行对象
|
||||||
|
const validateRowData = {
|
||||||
|
startNo: editForm.startNo,
|
||||||
|
endNo: editForm.endNo,
|
||||||
|
usedNo: editForm.usedNo,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证行数据(编辑时排除当前记录的 id,避免误判为重复)
|
||||||
|
const rowIndex = editForm.id ? tableData.value.findIndex(r => r.id === editForm.id) : -1
|
||||||
|
if (!validateRow(validateRowData, rowIndex, editForm.id)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 准备保存的数据
|
||||||
|
const saveData = {
|
||||||
|
id: editForm.id,
|
||||||
|
operatorId: editForm.operatorId,
|
||||||
|
operatorName: editForm.operatorName,
|
||||||
|
staffNo: editForm.staffNo,
|
||||||
|
receiveDate: convertDateForBackend(editForm.receiveDate),
|
||||||
|
startNo: editForm.startNo,
|
||||||
|
endNo: editForm.endNo,
|
||||||
|
usedNo: editForm.usedNo,
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
let res
|
||||||
|
if (saveData.id) {
|
||||||
|
// 更新
|
||||||
|
res = await updateOutpatientNo(saveData)
|
||||||
|
} else {
|
||||||
|
// 新增
|
||||||
|
res = await addOutpatientNo(saveData)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.code === 200) {
|
||||||
|
proxy.$modal.msgSuccess('保存成功')
|
||||||
|
editDialogVisible.value = false
|
||||||
|
getList()
|
||||||
|
} else {
|
||||||
|
// 显示后端返回的错误信息
|
||||||
|
const errorMsg = res.msg || res.message || '保存失败'
|
||||||
|
proxy.$modal.msgError(errorMsg)
|
||||||
|
if (saveData.id) {
|
||||||
|
logUpdate(saveData, false, errorMsg, getUserInfo())
|
||||||
|
} else {
|
||||||
|
logCreate(saveData, false, errorMsg, getUserInfo())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('保存失败:', error)
|
||||||
|
// 从错误对象中提取错误信息
|
||||||
|
let errorMsg = '保存失败'
|
||||||
|
|
||||||
|
// 优先从 response.data.msg 获取
|
||||||
|
if (error.response?.data?.msg) {
|
||||||
|
errorMsg = error.response.data.msg
|
||||||
|
}
|
||||||
|
// 其次从 error.message 获取(request.js 会通过 new Error(msg) 抛出)
|
||||||
|
else if (error.message) {
|
||||||
|
// 如果 error.message 包含 "Error: " 前缀,去掉它
|
||||||
|
errorMsg = error.message.replace(/^Error:\s*/, '')
|
||||||
|
}
|
||||||
|
// 最后尝试从 error.msg 获取
|
||||||
|
else if (error.msg) {
|
||||||
|
errorMsg = error.msg
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示错误信息
|
||||||
|
proxy.$modal.msgError(errorMsg)
|
||||||
|
|
||||||
|
// 记录日志
|
||||||
|
if (saveData.id) {
|
||||||
|
logUpdate(saveData, false, errorMsg, getUserInfo())
|
||||||
|
} else {
|
||||||
|
logCreate(saveData, false, errorMsg, getUserInfo())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 新增时,起始号码变化时自动设置使用号码为起始号码
|
// 新增时,起始号码变化时自动设置使用号码为起始号码
|
||||||
@@ -280,29 +435,6 @@ function tableRowClassName({ row }) {
|
|||||||
return row._error ? 'error-row' : ''
|
return row._error ? 'error-row' : ''
|
||||||
}
|
}
|
||||||
|
|
||||||
function openEdit(row, index) {
|
|
||||||
editIndex.value = index
|
|
||||||
dialogTitle.value = '编辑门诊号码段'
|
|
||||||
editForm.receiveDate = row.receiveDate
|
|
||||||
editForm.startNo = row.startNo
|
|
||||||
editForm.endNo = row.endNo
|
|
||||||
editForm.usedNo = row.usedNo
|
|
||||||
editForm.operatorName = row.operatorName
|
|
||||||
editForm.staffNo = row.staffNo
|
|
||||||
dialogVisible.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
function confirmEdit() {
|
|
||||||
const tmp = { ...tableData.value[editIndex.value], ...editForm }
|
|
||||||
if (!validateRow(tmp, editIndex.value)) return
|
|
||||||
tableData.value[editIndex.value] = {
|
|
||||||
...tableData.value[editIndex.value],
|
|
||||||
...editForm,
|
|
||||||
_dirty: true, // 标记为已修改,顶部保存时提交
|
|
||||||
}
|
|
||||||
dialogVisible.value = false
|
|
||||||
}
|
|
||||||
|
|
||||||
// 字母前缀识别规则 - 从末位往前找到第一个字母
|
// 字母前缀识别规则 - 从末位往前找到第一个字母
|
||||||
function extractPrefix(value) {
|
function extractPrefix(value) {
|
||||||
if (!value) return ''
|
if (!value) return ''
|
||||||
@@ -350,7 +482,7 @@ function isTailDigitsValid(value) {
|
|||||||
function validateNumField(row, field, rowIndex) {
|
function validateNumField(row, field, rowIndex) {
|
||||||
if (!isTailDigitsValid(row[field])) {
|
if (!isTailDigitsValid(row[field])) {
|
||||||
const idxInTable = typeof rowIndex === 'number' ? rowIndex : tableData.value.indexOf(row)
|
const idxInTable = typeof rowIndex === 'number' ? rowIndex : tableData.value.indexOf(row)
|
||||||
const lineNo = idxInTable >= 0 ? idxInTable + 1 : (editIndex.value >= 0 ? editIndex.value + 1 : undefined)
|
const lineNo = idxInTable >= 0 ? idxInTable + 1 : undefined
|
||||||
const msg = lineNo ? `第【${lineNo}】行数据中,最大位数为12位,且必须以数字结尾!` : '最大位数为12位,且必须以数字结尾'
|
const msg = lineNo ? `第【${lineNo}】行数据中,最大位数为12位,且必须以数字结尾!` : '最大位数为12位,且必须以数字结尾'
|
||||||
alertWarn(msg)
|
alertWarn(msg)
|
||||||
row._error = true
|
row._error = true
|
||||||
@@ -376,11 +508,11 @@ function onNumberInput(row, field) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateRow(row, rowIndex) {
|
function validateRow(row, rowIndex, excludeId = null) {
|
||||||
row._error = false
|
row._error = false
|
||||||
if (!lengthWithinLimit(row.startNo) || !lengthWithinLimit(row.endNo) || !lengthWithinLimit(row.usedNo)) {
|
if (!lengthWithinLimit(row.startNo) || !lengthWithinLimit(row.endNo) || !lengthWithinLimit(row.usedNo)) {
|
||||||
const idxInTable = typeof rowIndex === 'number' ? rowIndex : tableData.value.indexOf(row)
|
const idxInTable = typeof rowIndex === 'number' ? rowIndex : tableData.value.indexOf(row)
|
||||||
const lineNo = idxInTable >= 0 ? idxInTable + 1 : (editIndex.value >= 0 ? editIndex.value + 1 : undefined)
|
const lineNo = idxInTable >= 0 ? idxInTable + 1 : undefined
|
||||||
const msg = lineNo ? `第【${lineNo}】行数据中,最大位数为12位,且必须以数字结尾!` : '最大位数为12位,且必须以数字结尾'
|
const msg = lineNo ? `第【${lineNo}】行数据中,最大位数为12位,且必须以数字结尾!` : '最大位数为12位,且必须以数字结尾'
|
||||||
alertWarn(msg)
|
alertWarn(msg)
|
||||||
row._error = true
|
row._error = true
|
||||||
@@ -388,7 +520,7 @@ function validateRow(row, rowIndex) {
|
|||||||
}
|
}
|
||||||
if ((row.startNo?.length || 0) !== (row.endNo?.length || 0)) {
|
if ((row.startNo?.length || 0) !== (row.endNo?.length || 0)) {
|
||||||
const idxInTable = typeof rowIndex === 'number' ? rowIndex : tableData.value.indexOf(row)
|
const idxInTable = typeof rowIndex === 'number' ? rowIndex : tableData.value.indexOf(row)
|
||||||
const lineNo = idxInTable >= 0 ? idxInTable + 1 : (editIndex.value >= 0 ? editIndex.value + 1 : undefined)
|
const lineNo = idxInTable >= 0 ? idxInTable + 1 : undefined
|
||||||
const msg = lineNo ? `第【${lineNo}】行数据中,起始号码与终止号码长度必须一致,请修改!` : '起始号码与终止号码长度必须一致'
|
const msg = lineNo ? `第【${lineNo}】行数据中,起始号码与终止号码长度必须一致,请修改!` : '起始号码与终止号码长度必须一致'
|
||||||
alertWarn(msg)
|
alertWarn(msg)
|
||||||
row._error = true
|
row._error = true
|
||||||
@@ -399,7 +531,7 @@ function validateRow(row, rowIndex) {
|
|||||||
const p3 = extractPrefix(row.usedNo)
|
const p3 = extractPrefix(row.usedNo)
|
||||||
if (!(p1 === p2 && p2 === p3)) {
|
if (!(p1 === p2 && p2 === p3)) {
|
||||||
const idxInTable = typeof rowIndex === 'number' ? rowIndex : tableData.value.indexOf(row)
|
const idxInTable = typeof rowIndex === 'number' ? rowIndex : tableData.value.indexOf(row)
|
||||||
const lineNo = idxInTable >= 0 ? idxInTable + 1 : (editIndex.value >= 0 ? editIndex.value + 1 : undefined)
|
const lineNo = idxInTable >= 0 ? idxInTable + 1 : undefined
|
||||||
const msg = lineNo ? `第【${lineNo}】行数据中,门诊号码的字母前缀必须相同,请修改!` : '行数据中,门诊号码的字母前缀必须相同,请修改!'
|
const msg = lineNo ? `第【${lineNo}】行数据中,门诊号码的字母前缀必须相同,请修改!` : '行数据中,门诊号码的字母前缀必须相同,请修改!'
|
||||||
alertWarn(msg)
|
alertWarn(msg)
|
||||||
row._error = true
|
row._error = true
|
||||||
@@ -409,25 +541,29 @@ function validateRow(row, rowIndex) {
|
|||||||
const eNum = extractTailNumber(row.endNo)
|
const eNum = extractTailNumber(row.endNo)
|
||||||
if (Number.isNaN(sNum) || Number.isNaN(eNum) || sNum > eNum) {
|
if (Number.isNaN(sNum) || Number.isNaN(eNum) || sNum > eNum) {
|
||||||
const idxInTable = typeof rowIndex === 'number' ? rowIndex : tableData.value.indexOf(row)
|
const idxInTable = typeof rowIndex === 'number' ? rowIndex : tableData.value.indexOf(row)
|
||||||
const lineNo = idxInTable >= 0 ? idxInTable + 1 : (editIndex.value >= 0 ? editIndex.value + 1 : undefined)
|
const lineNo = idxInTable >= 0 ? idxInTable + 1 : undefined
|
||||||
const msg = lineNo ? `第【${lineNo}】行数据中,起始/终止号码不合法` : '起始/终止号码不合法'
|
const msg = lineNo ? `第【${lineNo}】行数据中,起始/终止号码不合法` : '起始/终止号码不合法'
|
||||||
alertWarn(msg)
|
alertWarn(msg)
|
||||||
row._error = true
|
row._error = true
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
// 放宽:不再强制“使用号码”必须处于起始与终止范围内
|
// 放宽:不再强制"使用号码"必须处于起始与终止范围内
|
||||||
const prefix = p1
|
const prefix = p1
|
||||||
for (let i = 0; i < tableData.value.length; i++) {
|
for (let i = 0; i < tableData.value.length; i++) {
|
||||||
const other = tableData.value[i]
|
const other = tableData.value[i]
|
||||||
// 跳过自身:当从弹窗校验时 row 为临时对象,需用下标判断
|
// 跳过自身:通过 rowIndex、row 对象比较或 excludeId 排除
|
||||||
if ((typeof rowIndex === 'number' && i === rowIndex) || other === row || !other.startNo || !other.endNo) continue
|
if ((typeof rowIndex === 'number' && i === rowIndex) ||
|
||||||
|
other === row ||
|
||||||
|
!other.startNo ||
|
||||||
|
!other.endNo ||
|
||||||
|
(excludeId && other.id === excludeId)) continue
|
||||||
if (extractPrefix(other.startNo) !== prefix) continue
|
if (extractPrefix(other.startNo) !== prefix) continue
|
||||||
const os = extractTailNumber(other.startNo)
|
const os = extractTailNumber(other.startNo)
|
||||||
const oe = extractTailNumber(other.endNo)
|
const oe = extractTailNumber(other.endNo)
|
||||||
if (!Number.isNaN(os) && !Number.isNaN(oe)) {
|
if (!Number.isNaN(os) && !Number.isNaN(oe)) {
|
||||||
if (rangesOverlap(sNum, eNum, os, oe)) {
|
if (rangesOverlap(sNum, eNum, os, oe)) {
|
||||||
const idxInTable = typeof rowIndex === 'number' ? rowIndex : tableData.value.indexOf(row)
|
const idxInTable = typeof rowIndex === 'number' ? rowIndex : tableData.value.indexOf(row)
|
||||||
const lineNo = idxInTable >= 0 ? idxInTable + 1 : (editIndex.value >= 0 ? editIndex.value + 1 : undefined)
|
const lineNo = idxInTable >= 0 ? idxInTable + 1 : undefined
|
||||||
const msg = lineNo ? `第【${lineNo}】行数据中,门诊号码和【${i + 1}】行的门诊号码有冲突,请修改!` : '门诊号码设置重复!'
|
const msg = lineNo ? `第【${lineNo}】行数据中,门诊号码和【${i + 1}】行的门诊号码有冲突,请修改!` : '门诊号码设置重复!'
|
||||||
alertWarn(msg)
|
alertWarn(msg)
|
||||||
row._error = true
|
row._error = true
|
||||||
@@ -438,90 +574,233 @@ function validateRow(row, rowIndex) {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
function onSave(row) {
|
async function onSave(row) {
|
||||||
const rows = row ? [row] : tableData.value.filter(r => ids.value.includes(r.id) || r._dirty || r._editing)
|
const rows = row ? [row] : tableData.value.filter(r => ids.value.includes(r.id) || r._dirty || r._editing)
|
||||||
if (!rows.length) return
|
if (!rows.length) {
|
||||||
for (const r of rows) {
|
proxy.$modal.msgWarning('没有可保存的数据')
|
||||||
const idx = tableData.value.indexOf(r)
|
return
|
||||||
if (!validateRow(r, idx)) return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 准备保存的数据
|
// 前端校验
|
||||||
|
for (const r of rows) {
|
||||||
|
const idx = tableData.value.indexOf(r)
|
||||||
|
if (!validateRow(r, idx, r.id)) return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 准备保存的数据(将日期格式转换为后端需要的格式)
|
||||||
const saveData = rows.map((r) => ({
|
const saveData = rows.map((r) => ({
|
||||||
id: r.id,
|
id: r.id,
|
||||||
operatorId: r.operatorId,
|
operatorId: r.operatorId,
|
||||||
operatorName: r.operatorName,
|
operatorName: r.operatorName,
|
||||||
staffNo: r.staffNo,
|
staffNo: r.staffNo,
|
||||||
receiveDate: r.receiveDate,
|
receiveDate: convertDateForBackend(r.receiveDate), // 转换为 yyyy-MM-dd 格式
|
||||||
startNo: r.startNo,
|
startNo: r.startNo,
|
||||||
endNo: r.endNo,
|
endNo: r.endNo,
|
||||||
usedNo: r.usedNo,
|
usedNo: r.usedNo,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
const ok = lcUpsertMany(saveData)
|
// 批量保存
|
||||||
if (!ok) {
|
let successCount = 0
|
||||||
// 记录失败的操作日志
|
let failCount = 0
|
||||||
for (const record of saveData) {
|
|
||||||
if (record.id) {
|
|
||||||
logUpdate(record, false, '门诊号码设置重复', getUserInfo())
|
|
||||||
} else {
|
|
||||||
logCreate(record, false, '门诊号码设置重复', getUserInfo())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 记录成功的操作日志
|
|
||||||
for (const record of saveData) {
|
for (const record of saveData) {
|
||||||
|
try {
|
||||||
|
let res
|
||||||
if (record.id) {
|
if (record.id) {
|
||||||
|
// 更新
|
||||||
|
res = await updateOutpatientNo(record)
|
||||||
|
if (res.code === 200) {
|
||||||
logUpdate(record, true, null, getUserInfo())
|
logUpdate(record, true, null, getUserInfo())
|
||||||
|
successCount++
|
||||||
} else {
|
} else {
|
||||||
|
const errorMsg = res.msg || res.message || '保存失败'
|
||||||
|
proxy.$modal.msgError(errorMsg)
|
||||||
|
logUpdate(record, false, errorMsg, getUserInfo())
|
||||||
|
failCount++
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 新增
|
||||||
|
res = await addOutpatientNo(record)
|
||||||
|
if (res.code === 200) {
|
||||||
logCreate(record, true, null, getUserInfo())
|
logCreate(record, true, null, getUserInfo())
|
||||||
|
successCount++
|
||||||
|
} else {
|
||||||
|
const errorMsg = res.msg || res.message || '保存失败'
|
||||||
|
proxy.$modal.msgError(errorMsg)
|
||||||
|
logCreate(record, false, errorMsg, getUserInfo())
|
||||||
|
failCount++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('保存失败:', error)
|
||||||
|
// 从错误对象中提取错误信息
|
||||||
|
let errorMsg = '保存失败'
|
||||||
|
if (error.response?.data?.msg) {
|
||||||
|
errorMsg = error.response.data.msg
|
||||||
|
} else if (error.message) {
|
||||||
|
errorMsg = error.message
|
||||||
|
} else if (error.msg) {
|
||||||
|
errorMsg = error.msg
|
||||||
|
}
|
||||||
|
proxy.$modal.msgError(errorMsg)
|
||||||
|
if (record.id) {
|
||||||
|
logUpdate(record, false, errorMsg, getUserInfo())
|
||||||
|
} else {
|
||||||
|
logCreate(record, false, errorMsg, getUserInfo())
|
||||||
|
}
|
||||||
|
failCount++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (proxy.$modal?.alertSuccess) {
|
if (successCount > 0) {
|
||||||
proxy.$modal.alertSuccess('保存成功!')
|
proxy.$modal.msgSuccess(`保存成功${successCount}条`)
|
||||||
} else {
|
// 保存成功后,退出编辑状态
|
||||||
proxy.$message.success('保存成功')
|
rows.forEach(r => {
|
||||||
|
r._editing = false
|
||||||
|
r._dirty = false
|
||||||
|
r._originalData = null // 清除原始数据
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
if (failCount > 0) {
|
||||||
|
proxy.$modal.msgError(`保存失败${failCount}条`)
|
||||||
|
}
|
||||||
|
|
||||||
getList()
|
getList()
|
||||||
}
|
}
|
||||||
|
|
||||||
function onDelete() {
|
async function onDelete() {
|
||||||
const rows = tableData.value.filter((r) => ids.value.includes(r.id))
|
console.log('删除操作 - 选中的ID列表:', ids.value)
|
||||||
if (!rows.length) return
|
console.log('删除操作 - 表格数据:', tableData.value.map(r => ({ id: r.id, operatorId: r.operatorId })))
|
||||||
|
|
||||||
// 双重校验(归属权+使用状态)
|
const rows = tableData.value.filter((r) => ids.value.includes(r.id))
|
||||||
|
console.log('删除操作 - 筛选后的行数据:', rows.map(r => ({ id: r.id, operatorId: r.operatorId })))
|
||||||
|
|
||||||
|
if (!rows.length) {
|
||||||
|
proxy.$modal.msgWarning('请选择要删除的数据')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 前端预校验(归属权+使用状态)
|
||||||
for (const r of rows) {
|
for (const r of rows) {
|
||||||
|
console.log('检查删除权限 - 行数据:', {
|
||||||
|
id: r.id,
|
||||||
|
operatorId: r.operatorId,
|
||||||
|
operatorIdType: typeof r.operatorId,
|
||||||
|
userStoreId: userStore.id,
|
||||||
|
userStoreIdType: typeof userStore.id,
|
||||||
|
usedNo: r.usedNo,
|
||||||
|
startNo: r.startNo,
|
||||||
|
usedNoType: typeof r.usedNo,
|
||||||
|
startNoType: typeof r.startNo
|
||||||
|
})
|
||||||
|
|
||||||
const canDeleteSelf = String(r.operatorId) === String(userStore.id)
|
const canDeleteSelf = String(r.operatorId) === String(userStore.id)
|
||||||
const neverUsed = r.usedNo === r.startNo
|
// 确保字符串比较,避免类型问题
|
||||||
|
const neverUsed = String(r.usedNo || '') === String(r.startNo || '')
|
||||||
|
|
||||||
if (!canDeleteSelf) {
|
if (!canDeleteSelf) {
|
||||||
// 权限不足提示
|
console.warn('删除权限检查失败:', {
|
||||||
|
operatorId: r.operatorId,
|
||||||
|
userStoreId: userStore.id,
|
||||||
|
canDeleteSelf
|
||||||
|
})
|
||||||
alertWarn('只能删除自己维护的门诊号码段')
|
alertWarn('只能删除自己维护的门诊号码段')
|
||||||
logDelete(rows, false, '只能删除自己维护的门诊号码段', getUserInfo())
|
logDelete(rows, false, '只能删除自己维护的门诊号码段', getUserInfo())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (!neverUsed) {
|
if (!neverUsed) {
|
||||||
// 已使用提示
|
console.warn('使用状态检查失败:', {
|
||||||
|
usedNo: r.usedNo,
|
||||||
|
startNo: r.startNo,
|
||||||
|
neverUsed
|
||||||
|
})
|
||||||
alertWarn('已有门诊号码段已有使用的门诊号码,请核对!')
|
alertWarn('已有门诊号码段已有使用的门诊号码,请核对!')
|
||||||
logDelete(rows, false, '已有门诊号码段已有使用的门诊号码', getUserInfo())
|
logDelete(rows, false, '已有门诊号码段已有使用的门诊号码', getUserInfo())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const doRealDelete = () => {
|
const doRealDelete = async () => {
|
||||||
lcDeleteByIds(rows.map((r) => r.id))
|
try {
|
||||||
|
// 处理大整数 ID:保持为字符串或使用 BigInt,避免精度丢失
|
||||||
//记录成功的删除操作日志
|
// JavaScript 的 Number.MAX_SAFE_INTEGER = 9007199254740991
|
||||||
logDelete(rows, true, null, getUserInfo())
|
// 如果 ID 超过这个值,转换为数字会丢失精度
|
||||||
|
const idsToDelete = rows
|
||||||
if (proxy.$modal?.alertSuccess) {
|
.map((r) => r.id)
|
||||||
proxy.$modal.alertSuccess('删除成功')
|
.filter(id => id != null && id !== undefined)
|
||||||
} else {
|
.map(id => {
|
||||||
proxy.$message.success('删除成功')
|
// 如果 ID 是字符串,检查是否需要转换为数字
|
||||||
|
if (typeof id === 'string') {
|
||||||
|
// 尝试转换为数字,但如果超过安全整数范围,保持为字符串
|
||||||
|
const numId = parseInt(id, 10)
|
||||||
|
if (!isNaN(numId) && numId <= Number.MAX_SAFE_INTEGER) {
|
||||||
|
return numId
|
||||||
}
|
}
|
||||||
|
// 大整数保持为字符串,后端应该能处理
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
// 如果已经是数字,检查是否超过安全范围
|
||||||
|
if (typeof id === 'number') {
|
||||||
|
if (id > Number.MAX_SAFE_INTEGER) {
|
||||||
|
// 超过安全范围,转换为字符串
|
||||||
|
return String(id)
|
||||||
|
}
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
// 其他类型,尝试转换
|
||||||
|
return id
|
||||||
|
})
|
||||||
|
.filter(id => id != null && id !== undefined)
|
||||||
|
|
||||||
|
if (idsToDelete.length === 0) {
|
||||||
|
proxy.$modal.msgWarning('没有可删除的数据')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('准备删除的ID列表:', idsToDelete)
|
||||||
|
console.log('删除请求数据:', JSON.stringify({ ids: idsToDelete }))
|
||||||
|
console.log('删除请求数据类型:', idsToDelete.map(id => ({ value: id, type: typeof id, stringValue: String(id) })))
|
||||||
|
|
||||||
|
const res = await deleteOutpatientNo({ ids: idsToDelete })
|
||||||
|
|
||||||
|
console.log('删除响应:', res)
|
||||||
|
console.log('删除响应code:', res?.code)
|
||||||
|
console.log('删除响应msg:', res?.msg)
|
||||||
|
|
||||||
|
if (res && (res.code === 200 || res.code === 0)) {
|
||||||
|
logDelete(rows, true, null, getUserInfo())
|
||||||
|
proxy.$modal.msgSuccess('删除成功')
|
||||||
getList()
|
getList()
|
||||||
|
} else {
|
||||||
|
const errorMsg = res?.msg || res?.message || '删除失败'
|
||||||
|
logDelete(rows, false, errorMsg, getUserInfo())
|
||||||
|
proxy.$modal.msgError(errorMsg)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('删除失败:', error)
|
||||||
|
// 从错误对象中提取错误信息
|
||||||
|
let errorMsg = '删除失败'
|
||||||
|
|
||||||
|
// 优先从 response.data.msg 获取
|
||||||
|
if (error.response?.data?.msg) {
|
||||||
|
errorMsg = error.response.data.msg
|
||||||
|
}
|
||||||
|
// 其次从 error.message 获取(request.js 会通过 new Error(msg) 抛出)
|
||||||
|
else if (error.message) {
|
||||||
|
// 如果 error.message 包含 "Error: " 前缀,去掉它
|
||||||
|
errorMsg = error.message.replace(/^Error:\s*/, '')
|
||||||
|
}
|
||||||
|
// 最后尝试从 error.msg 获取
|
||||||
|
else if (error.msg) {
|
||||||
|
errorMsg = error.msg
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示错误信息(参考 PackageManagement 的实现方式)
|
||||||
|
proxy.$modal.msgError('删除失败: ' + errorMsg)
|
||||||
|
|
||||||
|
// 记录日志
|
||||||
|
logDelete(rows, false, errorMsg, getUserInfo())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (proxy.$modal?.confirm) {
|
if (proxy.$modal?.confirm) {
|
||||||
@@ -537,115 +816,48 @@ function getList() {
|
|||||||
loading.value = true
|
loading.value = true
|
||||||
queryParams.value.onlySelf = !viewAll.value
|
queryParams.value.onlySelf = !viewAll.value
|
||||||
|
|
||||||
// 先尝试调用后端API
|
// 调用后端API
|
||||||
listOutpatientNo(queryParams.value).then((res) => {
|
listOutpatientNo(queryParams.value).then((res) => {
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
tableData.value = (res.data?.records || res.data || []).map((it) => ({
|
tableData.value = (res.data?.records || res.data || []).map((it) => {
|
||||||
|
// 处理大整数 ID:如果 ID 超过 JavaScript 安全整数范围,保持为字符串
|
||||||
|
let id = it.id
|
||||||
|
if (typeof id === 'number' && id > Number.MAX_SAFE_INTEGER) {
|
||||||
|
// 数字超过安全范围,转换为字符串以避免精度丢失
|
||||||
|
id = String(id)
|
||||||
|
} else if (typeof id === 'number') {
|
||||||
|
// 数字在安全范围内,保持为数字
|
||||||
|
id = id
|
||||||
|
} else {
|
||||||
|
// 已经是字符串或其他类型,保持原样
|
||||||
|
id = id
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
...it,
|
...it,
|
||||||
|
id: id, // 确保 ID 正确处理
|
||||||
_editing: false,
|
_editing: false,
|
||||||
_error: false,
|
_error: false,
|
||||||
_dirty: false,
|
_dirty: false,
|
||||||
}))
|
// 确保日期格式正确:后端返回 yyyy-MM-dd,转换为 YYYY.MM.DD 用于显示
|
||||||
|
receiveDate: it.receiveDate ? formatReceiveDate(it.receiveDate) : ''
|
||||||
|
}
|
||||||
|
})
|
||||||
total.value = res.data?.total || res.data?.length || 0
|
total.value = res.data?.total || res.data?.length || 0
|
||||||
|
|
||||||
// 记录查询操作日志
|
// 记录查询操作日志
|
||||||
logQuery(total.value, getUserInfo())
|
logQuery(total.value, getUserInfo())
|
||||||
} else {
|
} else {
|
||||||
// API返回错误,回退到localStorage
|
proxy.$modal.msgError(res.msg || '查询失败')
|
||||||
console.warn('后端API返回错误,使用localStorage数据')
|
|
||||||
loadFromLocalStorage()
|
|
||||||
}
|
}
|
||||||
loading.value = false
|
loading.value = false
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
// API调用失败(如404),回退到localStorage
|
console.error('查询门诊号码段失败:', error)
|
||||||
console.warn('后端API调用失败,使用localStorage数据:', error)
|
proxy.$modal.msgError('查询失败,请稍后重试')
|
||||||
loadFromLocalStorage()
|
loading.value = false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 从localStorage加载数据
|
|
||||||
function loadFromLocalStorage() {
|
|
||||||
const res = lcList({ ...queryParams.value })
|
|
||||||
tableData.value = res.records.map((it) => ({
|
|
||||||
...it,
|
|
||||||
_editing: false,
|
|
||||||
_error: false,
|
|
||||||
_dirty: false,
|
|
||||||
}))
|
|
||||||
total.value = res.total
|
|
||||||
|
|
||||||
// 记录查询操作日志
|
|
||||||
logQuery(total.value, getUserInfo())
|
|
||||||
loading.value = false
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 纯前端本地持久化方法(localStorage)
|
|
||||||
const STORAGE_KEY = 'ohis_outpatient_no_segments'
|
|
||||||
|
|
||||||
function lcReadAll() {
|
|
||||||
try {
|
|
||||||
const raw = localStorage.getItem(STORAGE_KEY)
|
|
||||||
const arr = raw ? JSON.parse(raw) : []
|
|
||||||
return Array.isArray(arr) ? arr : []
|
|
||||||
} catch (e) {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function lcWriteAll(list) {
|
|
||||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(list || []))
|
|
||||||
}
|
|
||||||
|
|
||||||
function lcList({ pageNo = 1, pageSize = 10, onlySelf = true }) {
|
|
||||||
const all = lcReadAll()
|
|
||||||
const filtered = onlySelf ? all.filter((x) => String(x.operatorId) === String(userStore.id)) : all
|
|
||||||
const start = (pageNo - 1) * pageSize
|
|
||||||
const end = start + pageSize
|
|
||||||
return { records: filtered.slice(start, end), total: filtered.length, all }
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkOverlapAll(row, all) {
|
|
||||||
const prefix = extractPrefix(row.startNo)
|
|
||||||
const sNum = extractTailNumber(row.startNo)
|
|
||||||
const eNum = extractTailNumber(row.endNo)
|
|
||||||
for (const it of all) {
|
|
||||||
if (row.id && it.id === row.id) continue
|
|
||||||
if (!it.startNo || !it.endNo) continue
|
|
||||||
if (extractPrefix(it.startNo) !== prefix) continue
|
|
||||||
const os = extractTailNumber(it.startNo)
|
|
||||||
const oe = extractTailNumber(it.endNo)
|
|
||||||
if (!Number.isNaN(os) && !Number.isNaN(oe)) {
|
|
||||||
if (rangesOverlap(sNum, eNum, os, oe)) return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
function lcUpsertMany(rows) {
|
|
||||||
const all = lcReadAll()
|
|
||||||
for (const r of rows) {
|
|
||||||
if (checkOverlapAll(r, all)) {
|
|
||||||
alertWarn('门诊号码设置重复!')
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if (!r.id) {
|
|
||||||
r.id = `${Date.now()}_${Math.random().toString(36).slice(2, 8)}`
|
|
||||||
}
|
|
||||||
const idx = all.findIndex((x) => x.id === r.id)
|
|
||||||
if (idx >= 0) all[idx] = { ...all[idx], ...r }
|
|
||||||
else all.push({ ...r })
|
|
||||||
}
|
|
||||||
lcWriteAll(all)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
function lcDeleteByIds(idList) {
|
|
||||||
const all = lcReadAll()
|
|
||||||
const remain = all.filter((x) => !idList.includes(x.id))
|
|
||||||
lcWriteAll(remain)
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@@ -653,17 +865,14 @@ function lcDeleteByIds(idList) {
|
|||||||
|
|
||||||
/* 外层容器 - 全屏显示 */
|
/* 外层容器 - 全屏显示 */
|
||||||
.outpatient-no-management-wrapper {
|
.outpatient-no-management-wrapper {
|
||||||
display: flex;
|
|
||||||
justify-content: flex-start;
|
|
||||||
align-items: flex-start;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: calc(100vh - 84px);
|
height: calc(100vh - 84px);
|
||||||
padding: 0;
|
|
||||||
background-color: #f0f0f0;
|
background-color: #f0f0f0;
|
||||||
overflow: hidden;
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 主容器 - 全屏宽度和高度 */
|
/* 主容器 - 全屏显示 */
|
||||||
.outpatient-no-management {
|
.outpatient-no-management {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@@ -865,28 +1074,6 @@ function lcDeleteByIds(idList) {
|
|||||||
background: linear-gradient(to bottom, #FFFEF8 0%, #F5F4EF 50%, #E5E4DF 100%);
|
background: linear-gradient(to bottom, #FFFEF8 0%, #F5F4EF 50%, #E5E4DF 100%);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 编辑弹窗样式 */
|
|
||||||
:deep(.el-dialog) {
|
|
||||||
border-radius: 0;
|
|
||||||
border: 2px solid #0055E5;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.el-dialog__header) {
|
|
||||||
background: linear-gradient(to bottom, #0055E5 0%, #0F3D8C 100%);
|
|
||||||
padding: 10px 15px;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.el-dialog__title) {
|
|
||||||
color: #FFFFFF;
|
|
||||||
font-weight: 700;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.el-dialog__close) {
|
|
||||||
color: #FFFFFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 表格容器样式调整 */
|
/* 表格容器样式调整 */
|
||||||
.table-content :deep(.el-table__body-wrapper) {
|
.table-content :deep(.el-table__body-wrapper) {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
|||||||
Reference in New Issue
Block a user