This commit is contained in:
Ledo 2025-10-07 18:39:32 +08:00
parent 060d627cba
commit 181dc83d4e
37 changed files with 4262 additions and 1050 deletions

View File

@ -98,6 +98,7 @@ public interface ErrorCodeConstants {
ErrorCode PLAN_SUB_NOT_EXISTS = new ErrorCode(1_007_002, "生产计划子项目不存在");
ErrorCode PLAN_TASK_NOT_EXISTS = new ErrorCode(1_007_003, "生产计划任务不存在");
ErrorCode PLAN_TASK_BOM_NOT_EXISTS = new ErrorCode(1_007_004, "生产计划任务Bom不存在");
//1_007_005已被占用
/************采购管理***********/
ErrorCode MATERIAL_PLAN_NOT_EXISTS = new ErrorCode(1_008_001, "物料需求计划不存在");
ErrorCode MATERIAL_PLAN_DETAIL_NOT_EXISTS = new ErrorCode(1_008_002, "物料需求计划物料详情不存在");

View File

@ -94,7 +94,12 @@ public class PlanSubController {
public CommonResult<Long> createPlanSub(@Valid @RequestBody PlanSubSaveReqVO createReqVO) {
return success(planSubService.createPlanSub(createReqVO));
}
@PostMapping("/operate")
@Operation(summary = "创建生产计划子项目")
@PreAuthorize("@ss.hasPermission('heli:plan-sub:create')")
public void operate(@RequestBody List<PlanSubSaveReqVO> list) {
planSubService.operate(list);
}
@PutMapping("/update")
@Operation(summary = "更新生产计划子项目")
@PreAuthorize("@ss.hasPermission('heli:plan-sub:update')")

View File

@ -147,5 +147,7 @@ public class PlanSubRespVO {
@Schema(description = "设计类型")
private int type;
private boolean hasSaveInBlankDetail;
private boolean hasSaveIn2DDetail;
private boolean hasSaveIn3DDetail;
}

View File

@ -15,7 +15,7 @@ import static com.chanko.yunxi.mes.framework.common.util.date.DateUtils.FORMAT_Y
@Data
public class PlanSubSaveReqVO {
@Schema(description = "自增字段,唯一", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "自增字段,唯一")
private Long id;
@Schema(description = "计划id", requiredMode = Schema.RequiredMode.REQUIRED)
@ -27,7 +27,7 @@ public class PlanSubSaveReqVO {
@Schema(description = "子项目id")
private Long projectSubId;
private String name;
@Schema(description = "子项目简称")
private String projectSubShortName;
@ -80,5 +80,7 @@ public class PlanSubSaveReqVO {
@Schema(description = "3D负责人")
private String threeDimOwner;
private boolean hasSaveInBlankDetail;
private boolean hasSaveIn2DDetail;
private boolean hasSaveIn3DDetail;
}

View File

@ -70,6 +70,8 @@ public class PlanSubDetailController {
return success(BeanUtils.toBean(planSubDetail, PlanSubDetailRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得生产计划子项目设计时间明细分页")
@PreAuthorize("@ss.hasPermission('heli:plan-sub-detail:query')")
@ -77,7 +79,13 @@ public class PlanSubDetailController {
PageResult<PlanSubDetailDO> pageResult = planSubDetailService.getPlanSubDetailPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, PlanSubDetailRespVO.class));
}
@GetMapping("/queryMaxDetail")
@Operation(summary = "获得生产计划子项目设计时间明细分页")
@PreAuthorize("@ss.hasPermission('heli:plan-sub-detail:query')")
public CommonResult<PlanSubDetailRespVO> queryMaxDetail(@Valid PlanSubDetailPageReqVO pageReqVO) {
PlanSubDetailDO pageResult = planSubDetailService.queryMaxDetail(pageReqVO);
return success(BeanUtils.toBean(pageResult, PlanSubDetailRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出生产计划子项目设计时间明细 Excel")
@PreAuthorize("@ss.hasPermission('heli:plan-sub-detail:export')")
@ -102,6 +110,33 @@ public class PlanSubDetailController {
public CommonResult modification(@Valid @RequestBody PlanSubDetailSaveReqVO updateReqVO) {
return planSubDetailService.modification(updateReqVO);
}
@GetMapping("/pageAddList")
@Operation(summary = "获得生产计划子项目设计时间明细分页")
@PreAuthorize("@ss.hasPermission('heli:plan-sub-detail:query')")
public CommonResult<PageResult<PlanSubDetailRespVO>> pageAddList(@Valid PlanSubDetailPageReqVO pageReqVO) {
PageResult<PlanSubDetailDO> pageResult = planSubDetailService.getPlanList(pageReqVO);
return success(BeanUtils.toBean(pageResult, PlanSubDetailRespVO.class));
}
@PostMapping("/chahuo")
@Operation(summary = "插活排程")
public CommonResult chahuo(@RequestBody PlanSubDetailSaveReqVO updateReqVO) {
return planSubDetailService.chahuoList(updateReqVO);
}
@PostMapping("/savechahuo")
@Operation(summary = "保存插活结果")
public CommonResult savechahuo(@RequestBody PlanSubDetailSaveReqVO updateReqVO) {
return planSubDetailService.savechahuoList(updateReqVO);
}
@PostMapping("/operate")
@Operation(summary = "操作页面总体数据")
public CommonResult operate(@RequestBody PlanSubDetailSaveReqVO updateReqVO) {
return planSubDetailService.operate(updateReqVO);
}
@PostMapping("/insertWork")
@Operation(summary = "插活")
public CommonResult insertWork(@Valid @RequestBody PlanSubDetailSaveReqVO updateReqVO) {

View File

@ -62,7 +62,18 @@ public class PlanSubDetailPageReqVO extends PageParam {
@Schema(description = "子项目名称,唯一", example = "张三")
private String name;
@Schema(description = "开始时间", requiredMode = Schema.RequiredMode.REQUIRED)
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime startTime;
@Schema(description = "是否是最大时间段")
private Integer flag;
}
private String queryDate;
@Schema(description = "项目编码", example = "26785")
private Long projectCode;
@Schema(description = "子项目名称" ,example = "s")
private String projectSubName;
private String customerBrief;
private String projectName;
private String planNo;
}

View File

@ -16,11 +16,11 @@ public class PlanSubDetailRespVO {
@Schema(description = "自增字段,唯一", requiredMode = Schema.RequiredMode.REQUIRED, example = "6922")
@ExcelProperty("自增字段,唯一")
private Long id;
private Integer flag;
@Schema(description = "计划id", requiredMode = Schema.RequiredMode.REQUIRED, example = "13863")
@ExcelProperty("计划id")
private Long projectPlanId;
private Long projectPlanSubId;
@Schema(description = "项目id", requiredMode = Schema.RequiredMode.REQUIRED, example = "11384")
@ExcelProperty("项目id")
private Long projectId;
@ -56,7 +56,7 @@ public class PlanSubDetailRespVO {
@Schema(description = "结束( 默认0 1结束")
@ExcelProperty("结束( 默认0 1结束")
private Boolean isOverProcess;
private Boolean userFlag = false;
@Schema(description = "时间段顺序")
@ExcelProperty("时间段顺序")
private Long seqNo;
@ -72,5 +72,12 @@ public class PlanSubDetailRespVO {
@Schema(description = "子项目名称,唯一", example = "张三")
@ExcelProperty("子项目名称,唯一")
private String name;
private LocalDateTime maxTime;
}
private String customerBrief;
private String projectName;
private String projectCode;
private String planNo;
private String projectSubName ;
}

View File

@ -13,14 +13,14 @@ import java.time.LocalDateTime;
@Data
public class PlanSubDetailSaveReqVO {
@Schema(description = "自增字段,唯一", requiredMode = Schema.RequiredMode.REQUIRED, example = "6922")
@Schema(description = "自增字段,唯一", example = "6922")
private Long id;
@Schema(description = "计划id", requiredMode = Schema.RequiredMode.REQUIRED, example = "13863")
@Schema(description = "计划id", example = "13863")
@NotNull(message = "计划id不能为空")
private Long projectPlanId;
@Schema(description = "项目id", requiredMode = Schema.RequiredMode.REQUIRED, example = "11384")
@Schema(description = "项目id", example = "11384")
@NotNull(message = "项目id不能为空")
private Long projectId;
@ -44,7 +44,7 @@ public class PlanSubDetailSaveReqVO {
@Schema(description = "结束( 默认0 1结束")
private Boolean isOverProcess;
private Long projectPlanSubId;
@Schema(description = "时间段顺序")
private Long seqNo;
@ -60,4 +60,5 @@ public class PlanSubDetailSaveReqVO {
private String isAdd;
@Schema(description = "是否新增")
private List<PlanSubDetailDO> list;
}

View File

@ -8,6 +8,7 @@ import com.chanko.yunxi.mes.framework.common.pojo.PageResult;
import com.chanko.yunxi.mes.framework.common.util.object.BeanUtils;
import com.chanko.yunxi.mes.framework.excel.core.util.ExcelUtils;
import com.chanko.yunxi.mes.framework.operatelog.core.annotations.OperateLog;
import com.chanko.yunxi.mes.framework.tenant.core.aop.TenantIgnore;
import com.chanko.yunxi.mes.module.heli.controller.admin.screen.vo.ScreenPageReqVO;
import com.chanko.yunxi.mes.module.heli.controller.admin.screen.vo.ScreenRespVO;
import com.chanko.yunxi.mes.module.heli.controller.admin.screen.vo.ScreenSaveReqVO;

View File

@ -52,7 +52,12 @@ public class ShopCalendarController {
PageResult<ShopCalendarDO> pageResult = shopCalendarService.searchRl(shopCalendarPageReqVO);
return success(BeanUtils.toBean(pageResult, ShopCalendarRespVO.class));
}
@GetMapping("/searchHoliday")
@Operation(summary = "查询是否节假日")
@PreAuthorize("@ss.hasPermission('heli:material:query')")
public CommonResult<Boolean> searchHoliday(@Valid ShopCalendarPageReqVO shopCalendarPageReqVO) {
return success(shopCalendarService.searchHoliday(shopCalendarPageReqVO));
}
@PostMapping("/insert")
@Operation(summary = "新增日历")
@Parameter(name = "dates", description = "年月", required = true)

View File

@ -31,6 +31,8 @@ public class ShopCalendarPageReqVO extends PageParam {
@Schema(description = "是否节假日")
private String ifjiejiari;
private String queryDate;
/*

View File

@ -213,5 +213,10 @@ public class PlanSubDO extends BaseDO {
private String businessLine;
@TableField(exist = false)
private int projectMonth;
@TableField(exist = false)
private boolean hasSaveInBlankDetail;
@TableField(exist = false)
private boolean hasSaveIn3DDetail;
@TableField(exist = false)
private boolean hasSaveIn2DDetail;
}

View File

@ -87,5 +87,17 @@ public class PlanSubDetailDO extends BaseDO {
private String isCha;
@TableField(exist = false)
private Integer flag;
}
private Long projectPlanSubId;
@TableField(exist = false)
private LocalDateTime maxTime;
@TableField(exist = false)
private String twoDimOwnerName;
@TableField(exist = false)
private String projectSubName;
@TableField(exist = false)
private String customerBrief;
@TableField(exist = false)
private String projectName;
@TableField(exist = false)
private String planNo;
}

View File

@ -6,15 +6,19 @@ import cn.hutool.core.util.ObjectUtil;
import com.chanko.yunxi.mes.framework.common.pojo.PageResult;
import com.chanko.yunxi.mes.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.chanko.yunxi.mes.framework.mybatis.core.mapper.BaseMapperX;
import com.chanko.yunxi.mes.framework.mybatis.core.query.MPJLambdaWrapperX;
import com.chanko.yunxi.mes.module.heli.dal.dataobject.customer.CustomerDO;
import com.chanko.yunxi.mes.module.heli.dal.dataobject.plan.PlanDO;
import com.chanko.yunxi.mes.module.heli.dal.dataobject.plansub.PlanSubDO;
import com.chanko.yunxi.mes.module.heli.dal.dataobject.plansubdetail.PlanSubDetailDO;
import com.chanko.yunxi.mes.module.heli.dal.dataobject.projectorder.ProjectOrderDO;
import com.chanko.yunxi.mes.module.heli.dal.dataobject.projectorder.ProjectOrderSubDO;
import com.chanko.yunxi.mes.module.heli.enums.ProcessDesignTypeEnum;
import com.chanko.yunxi.mes.module.system.dal.dataobject.user.AdminUserDO;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.apache.ibatis.annotations.Mapper;
import com.chanko.yunxi.mes.module.heli.controller.admin.plansubdetail.vo.*;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.util.StringUtils;
/**
@ -25,6 +29,16 @@ import org.springframework.util.StringUtils;
@Mapper
public interface PlanSubDetailMapper extends BaseMapperX<PlanSubDetailDO> {
default PageResult<PlanSubDetailDO> getPlanList(PlanSubDetailPageReqVO reqVO) {
MPJLambdaWrapper<PlanSubDetailDO> query = new MPJLambdaWrapper<>();
query.selectAll(PlanSubDetailDO.class)
.leftJoin(PlanDO.class,"pl",PlanDO::getId,PlanSubDetailDO::getProjectPlanId)
.select("pl.brief as customerBrief,pl.project_name as projectName,pl.code as projectCode,pl.plan_no as planNo")
.eq(ObjectUtil.isNotEmpty(reqVO.getProjectCode()), PlanDO::getCode, reqVO.getProjectCode())
.eq(ObjectUtil.isNotEmpty(reqVO.getProjectSubName()), PlanSubDetailDO::getName, reqVO.getProjectSubName());
return selectPage(reqVO, query);
}
default PageResult<PlanSubDetailDO> selectPage(PlanSubDetailPageReqVO reqVO) {
MPJLambdaWrapper<PlanSubDetailDO> query = new MPJLambdaWrapper<>();
@ -34,12 +48,24 @@ public interface PlanSubDetailMapper extends BaseMapperX<PlanSubDetailDO> {
.like(ObjectUtil.isNotEmpty(reqVO.getCode()), PlanSubDetailDO::getCode, reqVO.getCode())
.like(ObjectUtil.isNotEmpty(reqVO.getName()), PlanSubDetailDO::getName, reqVO.getName())
.eq(ObjectUtil.isNotEmpty(reqVO.getSubType()), PlanSubDetailDO::getSubType, reqVO.getSubType())
.and(QueryWrapper -> QueryWrapper.gt(PlanSubDetailDO::getStartTwoDimDate, reqVO.getStartTime())
.and(ObjectUtil.isNotEmpty(reqVO.getStartTime()),QueryWrapper -> QueryWrapper.ge(PlanSubDetailDO::getStartTwoDimDate, reqVO.getStartTime())
.or()
.lt( PlanSubDetailDO::getTwoDimDate, reqVO.getStartTime()))
.ge( PlanSubDetailDO::getTwoDimDate, reqVO.getStartTime()))
.in(PlanSubDetailDO::getIsOverProcess,0,2);
return selectPage(reqVO, query);
}
}
default List<PlanSubDetailDO> selectExistList(HashSet<String> ownerList) {
MPJLambdaWrapper<PlanSubDetailDO> query = new MPJLambdaWrapper<>();
query.selectAll(PlanSubDetailDO.class)
.select("psub.name as name")
.select("ad.nickname as twoDimOwnerName")
.leftJoin(PlanSubDO.class,"psub",PlanSubDO::getId,PlanSubDetailDO::getProjectPlanSubId)
.leftJoin(AdminUserDO.class,"ad",AdminUserDO::getId,PlanSubDetailDO::getTwoDimOwner)
.in(PlanSubDetailDO::getTwoDimOwner,ownerList)
.in(PlanSubDetailDO::getIsOverProcess,0,2);
return selectList(query);
}
}

View File

@ -23,6 +23,8 @@ public interface PlanSubService {
*/
Long createPlanSub(@Valid PlanSubSaveReqVO createReqVO);
void operate(List<PlanSubSaveReqVO> list);
/**
* 更新生产计划子项目
*

View File

@ -1,7 +1,9 @@
package com.chanko.yunxi.mes.module.heli.service.plansub;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.chanko.yunxi.mes.framework.common.exception.ErrorCode;
import com.chanko.yunxi.mes.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.chanko.yunxi.mes.module.heli.controller.admin.shopCalendar.vo.ShopCalendarPageReqVO;
import com.chanko.yunxi.mes.module.heli.dal.dataobject.plansubdetail.PlanSubDetailDO;
@ -12,6 +14,7 @@ import com.chanko.yunxi.mes.module.heli.dal.dataobject.shopCalendar.ShopCalendar
import com.chanko.yunxi.mes.module.heli.dal.mysql.plansubdetail.PlanSubDetailMapper;
import com.chanko.yunxi.mes.module.heli.dal.mysql.processbom.ProcessBomMapper;
import com.chanko.yunxi.mes.module.heli.dal.mysql.projectorder.ProjectOrderMapper;
import com.chanko.yunxi.mes.module.heli.dal.mysql.projectorder.ProjectOrderSubMapper;
import com.chanko.yunxi.mes.module.heli.dal.mysql.shopCalendar.ShopCalendarMapper;
import jodd.util.StringUtil;
import org.springframework.stereotype.Service;
@ -62,6 +65,218 @@ public class PlanSubServiceImpl implements PlanSubService {
return planSub.getId();
}
@Override
public void operate(List<PlanSubSaveReqVO> list) {
HashSet<String> userIds = new HashSet<>();
List<PlanSubSaveReqVO> inserList = new ArrayList<>();
for (PlanSubSaveReqVO planSubSaveReqVO : list) {
if (planSubSaveReqVO.isHasSaveInBlankDetail() && planSubSaveReqVO.isHasSaveIn2DDetail() && planSubSaveReqVO.isHasSaveIn3DDetail()){
}else{
inserList.add(planSubSaveReqVO);
}
if (planSubSaveReqVO.getTwoDimOwner() != null) {
userIds.add(planSubSaveReqVO.getTwoDimOwner());
}
if (planSubSaveReqVO.getThreeDimOwner() != null) {
userIds.add(planSubSaveReqVO.getThreeDimOwner());
}
if (planSubSaveReqVO.getBlankOwner() != null) {
userIds.add(planSubSaveReqVO.getBlankOwner());
}
}
List<PlanSubDetailDO> planSubDetailDOS = planSubDetailMapper.selectExistList(userIds);
List<PlanSubDetailDO> insertList = new ArrayList<>();
//检查冲突
checkForConflicts(list,planSubDetailDOS);
List<PlanSubDO> bean = BeanUtils.toBean(list, PlanSubDO.class);
planSubMapper.updateBatch(bean);
if (CollUtil.isNotEmpty(inserList)){
for (PlanSubSaveReqVO planSubSaveReqVO : inserList) {
ProjectOrderDO projectOrderDO = projectOrderMapper.selectById(planSubSaveReqVO.getProjectId());
List<PlanSubDetailDO> details = new ArrayList<>();
if (planSubSaveReqVO.getBlankDate() != null && !planSubSaveReqVO.isHasSaveInBlankDetail()){
//判断存不存在
PlanSubDetailDO inBlankDO = new PlanSubDetailDO();
inBlankDO.setProjectPlanId(planSubSaveReqVO.getProjectPlanId());
inBlankDO.setProjectId(planSubSaveReqVO.getProjectId());
inBlankDO.setProjectPlanSubId(planSubSaveReqVO.getId());
inBlankDO.setProjectSubCode(planSubSaveReqVO.getProjectSubCode());
inBlankDO.setTwoDimDate(planSubSaveReqVO.getBlankDate());
inBlankDO.setProjectSubId(planSubSaveReqVO.getProjectSubId());
inBlankDO.setStartTwoDimDate(planSubSaveReqVO.getStartBlankDate());
inBlankDO.setTwoDimOwner(Long.valueOf(planSubSaveReqVO.getBlankOwner()));
inBlankDO.setProjectPlanId(planSubSaveReqVO.getProjectPlanId());
inBlankDO.setSubType("BLUEPRINT_WORKBLANK");
inBlankDO.setSeqNo(1L);
inBlankDO.setDesignNum(Long.valueOf(planSubSaveReqVO.getBlankNum()));
inBlankDO.setName(planSubSaveReqVO.getName());
inBlankDO.setCode(projectOrderDO.getCode());
details.add(inBlankDO);
}
if (planSubSaveReqVO.getTwoDimDate() != null && !planSubSaveReqVO.isHasSaveIn2DDetail()){
PlanSubDetailDO in2DDO = new PlanSubDetailDO();
in2DDO.setProjectPlanId(planSubSaveReqVO.getProjectPlanId());
in2DDO.setProjectId(planSubSaveReqVO.getProjectId());
in2DDO.setProjectSubId(planSubSaveReqVO.getProjectSubId());
in2DDO.setProjectPlanSubId(planSubSaveReqVO.getId());
in2DDO.setProjectSubCode(planSubSaveReqVO.getProjectSubCode());
in2DDO.setTwoDimDate(planSubSaveReqVO.getTwoDimDate());
in2DDO.setProjectPlanId(planSubSaveReqVO.getProjectPlanId());
in2DDO.setStartTwoDimDate(planSubSaveReqVO.getStartTwoDimDate());
in2DDO.setTwoDimOwner(Long.valueOf(planSubSaveReqVO.getBlankOwner()));
in2DDO.setSubType("BLUEPRINT_2D");
in2DDO.setSeqNo(1L);
in2DDO.setDesignNum(Long.valueOf(planSubSaveReqVO.getBlankNum()));
in2DDO.setName(planSubSaveReqVO.getName());
in2DDO.setCode(projectOrderDO.getCode());
details.add(in2DDO);
}
if (planSubSaveReqVO.getThreeDimDate() != null && !planSubSaveReqVO.isHasSaveIn3DDetail()){
PlanSubDetailDO in3DDO = new PlanSubDetailDO();
in3DDO.setProjectPlanId(planSubSaveReqVO.getProjectPlanId());
in3DDO.setProjectId(planSubSaveReqVO.getProjectId());
in3DDO.setProjectPlanSubId(planSubSaveReqVO.getId());
in3DDO.setProjectPlanId(planSubSaveReqVO.getProjectPlanId());
in3DDO.setProjectSubId(planSubSaveReqVO.getProjectSubId());
in3DDO.setProjectSubCode(planSubSaveReqVO.getProjectSubCode());
in3DDO.setTwoDimDate(planSubSaveReqVO.getThreeDimDate());
in3DDO.setStartTwoDimDate(planSubSaveReqVO.getStartThreeDimDate());
in3DDO.setTwoDimOwner(Long.valueOf(planSubSaveReqVO.getBlankOwner()));
in3DDO.setSubType("BLUEPRINT_3D");
in3DDO.setSeqNo(1L);
in3DDO.setDesignNum(Long.valueOf(planSubSaveReqVO.getBlankNum()));
in3DDO.setName(planSubSaveReqVO.getName());
in3DDO.setCode(projectOrderDO.getCode());
details.add(in3DDO);
}
//把这个底下的都查出来
planSubDetailMapper.insertOrUpdateBatch(details);
}
}
}
/**
* 检查任务冲突
* @param processTasks list1, 新的工艺任务列表
* @param existingTasks list2, 已存在的任务列表
* @throws RuntimeException 如果发现任何时间冲突
*/
public void checkForConflicts(List<PlanSubSaveReqVO> processTasks, List<PlanSubDetailDO> existingTasks) {
// 为了提高查询效率 list2 Owner 转换为 Map
Map<Long, List<PlanSubDetailDO>> tasksByOwner = new HashMap<>();
for (PlanSubDetailDO task : existingTasks) {
tasksByOwner.computeIfAbsent(task.getTwoDimOwner(), k -> new ArrayList<>()).add(task);
}
// 1. 检查 list1 内部的时间冲突
checkInternalConflicts(processTasks);
// 2. 检查 list1 list2 之间的时间冲突
checkExternalConflicts(processTasks, tasksByOwner);
}
/**
* 检查 list1 内部同一责任人负责的工艺时间是否有交集
*/
private void checkInternalConflicts(List<PlanSubSaveReqVO> processTasks) {
// 将每个工艺任务拆分成独立的任务项方便统一检查
List<TaskItem> allNewItems = new ArrayList<>();
for (PlanSubSaveReqVO task : processTasks) {
if (!task.isHasSaveInBlankDetail() && task.getBlankOwner() != null && task.getStartBlankDate() != null && task.getBlankDate() != null) {
allNewItems.add(new TaskItem(Long.valueOf(task.getBlankOwner()), task.getStartBlankDate(), task.getBlankDate(), "毛坯",task.getProjectNameSim()));
}
if (!task.isHasSaveIn2DDetail() && task.getTwoDimOwner() != null && task.getStartTwoDimDate() != null && task.getTwoDimDate() != null) {
allNewItems.add(new TaskItem(Long.valueOf(task.getTwoDimOwner()), task.getStartTwoDimDate(), task.getTwoDimDate(), "2D",task.getProjectSubShortName()));
}
if (!task.isHasSaveIn3DDetail() && task.getThreeDimOwner() != null && task.getStartThreeDimDate() != null && task.getThreeDimDate() != null) {
allNewItems.add(new TaskItem(Long.valueOf(task.getThreeDimOwner()), task.getStartThreeDimDate(), task.getThreeDimDate(), "3D",task.getProjectSubShortName()));
}
}
// 对所有新任务项进行两两比较
for (int i = 0; i < allNewItems.size(); i++) {
TaskItem item1 = allNewItems.get(i);
for (int j = i + 1; j < allNewItems.size(); j++) {
TaskItem item2 = allNewItems.get(j);
// 只检查同一个责任人负责的任务
if (item1.owner.equals(item2.owner)) {
if (hasOverlap(item1.start, item1.end, item2.start, item2.end)) {
throw exception(new ErrorCode(1_007_006,"当前插入:"+item1.type+item1.start.toString().substring(0,10)+" -"+item1.end.toString().substring(0,10)+""+item2.type+item2.start.toString().substring(0,10)+item2.end.toString().substring(0,10)+"存在交集,请确认!"));
}
}
}
}
}
/**
* 检查 list1 的新任务是否与 list2 中已存在的任务冲突
*/
private void checkExternalConflicts(List<PlanSubSaveReqVO> processTasks, Map<Long, List<PlanSubDetailDO>> tasksByOwner) {
for (PlanSubSaveReqVO newTask : processTasks) {
// 检查毛坯任务
if (!newTask.isHasSaveInBlankDetail() && newTask.getBlankOwner() != null){
checkTaskAgainstExisting(Long.valueOf(newTask.getBlankOwner()), newTask.getStartBlankDate(), newTask.getBlankDate(), "BLUEPRINT_WORKBLANK", tasksByOwner);
}
// 检查2D任务
if (!newTask.isHasSaveIn2DDetail() && newTask.getTwoDimOwner() != null){
checkTaskAgainstExisting(Long.valueOf(newTask.getTwoDimOwner()), newTask.getStartTwoDimDate(), newTask.getTwoDimDate(), "BLUEPRINT_2D", tasksByOwner);
}
// 检查3D任务
if (!newTask.isHasSaveIn3DDetail() && newTask.getThreeDimOwner() != null){
checkTaskAgainstExisting(Long.valueOf(newTask.getThreeDimOwner()), newTask.getStartThreeDimDate(), newTask.getThreeDimDate(), "BLUEPRINT_3D", tasksByOwner);
}
}
}
/**
* 辅助方法检查单个新任务与已存在任务的冲突
*/
private void checkTaskAgainstExisting(Long owner, LocalDateTime start, LocalDateTime end, String taskType, Map<Long, List<PlanSubDetailDO>> tasksByOwner) {
if (owner == null || start == null || end == null) {
return; // 如果责任人或时间为空则无需检查
}
List<PlanSubDetailDO> existingTasksForOwner = tasksByOwner.get(owner);
if (existingTasksForOwner == null) {
return; // 如果该责任人没有已存在的任务则无需检查
}
String typeName = "";
if (taskType.equals("BLUEPRINT_3D")){
typeName = "3D";
}else if (taskType.equals("BLUEPRINT_2D")){
typeName = "2D";
}else if (taskType.equals("BLUEPRINT_WORKBLANK")){
typeName = "毛坯";
}
for (PlanSubDetailDO existingTask : existingTasksForOwner) {
if (hasOverlap(start, end, existingTask.getStartTwoDimDate(), existingTask.getTwoDimDate())) {
throw exception(new ErrorCode(1_007_006,"当前插入"+start.toString().substring(0,10)+" -"+end.toString().substring(0,10)+""+existingTask.getName()+"-"+typeName+existingTask.getStartTwoDimDate().toString().substring(0,10)+existingTask.getTwoDimDate().toString().substring(0,10)+"存在交集,请确认!"));
}
}
}
// 内部辅助类用于简化任务处理
private static class TaskItem {
final String projectName;
final Long owner;
final LocalDateTime start;
final LocalDateTime end;
final String type; // "毛坯", "2D", "3D"
TaskItem(Long owner, LocalDateTime start, LocalDateTime end, String type,String projectName) {
this.owner = owner;
this.start = start;
this.end = end;
this.type = type;
this.projectName = projectName;
}
}
@Override
public void updatePlanSub(PlanSubSaveReqVO updateReqVO) {
// 校验存在
@ -239,9 +454,6 @@ public class PlanSubServiceImpl implements PlanSubService {
}
//将所有信息查完之后根据createTime进行排序
planSubDOSs.sort(Comparator.comparing(PlanSubDO::getCreateTime));
// 输出排序后的结果
System.out.println("输出排序后结果");
planSubDOSs.forEach(System.out::println);
//用来获取日历时间段
String endTimes = null;//tableData.get(tableData.size()-1).getBlankDate().format(formatter);
@ -355,7 +567,14 @@ public class PlanSubServiceImpl implements PlanSubService {
LocalDateTime dateTime = LocalDateTime.parse(str, formatter);
return dateTime;
}
public static boolean hasOverlap(LocalDateTime start1, LocalDateTime end1, LocalDateTime start2, LocalDateTime end2) {
// 处理 null 如果任一时间为 null则认为该时间范围无效不产生交集
if (start1 == null || end1 == null || start2 == null || end2 == null) {
return false;
}
// 核心判断逻辑
return start1.compareTo(end2) <= 0 && start2.compareTo(end1) <= 0;
}
/*
* 转换日期方法
* */
@ -392,7 +611,27 @@ public class PlanSubServiceImpl implements PlanSubService {
@Override
public PageResult<PlanSubDO> getPlanSubPage(PlanSubPageReqVO pageReqVO) {
return planSubMapper.selectPage(pageReqVO);
PageResult<PlanSubDO> planSubDOPageResult = planSubMapper.selectPage(pageReqVO);
List<PlanSubDO> list = planSubDOPageResult.getList();
for (PlanSubDO planSubDO : list) {
List<PlanSubDetailDO> planSubDetailDOS1 = planSubDetailMapper.selectList(new LambdaQueryWrapperX<PlanSubDetailDO>().eq(PlanSubDetailDO::getProjectPlanSubId, planSubDO.getId())
.eq(PlanSubDetailDO::getSubType,"BLUEPRINT_WORKBLANK"));
List<PlanSubDetailDO> planSubDetailDOS2 = planSubDetailMapper.selectList(new LambdaQueryWrapperX<PlanSubDetailDO>().eq(PlanSubDetailDO::getProjectPlanSubId, planSubDO.getId())
.eq(PlanSubDetailDO::getSubType,"BLUEPRINT_2D"));
List<PlanSubDetailDO> planSubDetailDOS3 = planSubDetailMapper.selectList(new LambdaQueryWrapperX<PlanSubDetailDO>().eq(PlanSubDetailDO::getProjectPlanSubId, planSubDO.getId())
.eq(PlanSubDetailDO::getSubType,"BLUEPRINT_3D"));
if (CollUtil.isNotEmpty(planSubDetailDOS1)) {
planSubDO.setHasSaveInBlankDetail(true);
}
if (CollUtil.isNotEmpty(planSubDetailDOS2)) {
planSubDO.setHasSaveIn2DDetail(true);
}
if (CollUtil.isNotEmpty(planSubDetailDOS3)) {
planSubDO.setHasSaveIn3DDetail(true);
}
}
return planSubDOPageResult;
}
}

View File

@ -54,9 +54,14 @@ public interface PlanSubDetailService {
*/
PageResult<PlanSubDetailDO> getPlanSubDetailPage(PlanSubDetailPageReqVO pageReqVO);
PageResult<PlanSubDetailDO> getPlanList(PlanSubDetailPageReqVO pageReqVO);
PlanSubDetailDO queryMaxDetail(PlanSubDetailPageReqVO pageReqVO);
Integer getSearchRlTs(String startDateTime);
CommonResult chahuoList(PlanSubDetailSaveReqVO updateReqVO);
CommonResult savechahuoList(PlanSubDetailSaveReqVO updateReqVO);
CommonResult modification(PlanSubDetailSaveReqVO updateReqVO);
CommonResult operate(PlanSubDetailSaveReqVO updateReqVO);
CommonResult insertWork(PlanSubDetailSaveReqVO updateReqVO);
}

View File

@ -1,21 +1,29 @@
package com.chanko.yunxi.mes.module.heli.service.plansubdetail;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.chanko.yunxi.mes.framework.common.pojo.CommonResult;
import com.chanko.yunxi.mes.module.heli.dal.dataobject.plan.PlanDO;
import com.chanko.yunxi.mes.module.heli.dal.dataobject.plansub.PlanSubDO;
import com.chanko.yunxi.mes.module.heli.dal.dataobject.purchaseordernodetail.PurchaseOrderNoDetailDO;
import com.chanko.yunxi.mes.module.heli.dal.dataobject.shopCalendar.ShopCalendarDO;
import com.chanko.yunxi.mes.module.heli.dal.mysql.plansub.PlanSubMapper;
import com.chanko.yunxi.mes.module.heli.dal.mysql.processdesign.ProcessDesignMapper;
import com.chanko.yunxi.mes.module.heli.dal.mysql.shopCalendar.ShopCalendarMapper;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;
@ -45,6 +53,8 @@ public class PlanSubDetailServiceImpl implements PlanSubDetailService {
private ShopCalendarMapper shopCalendarMapper;
@Resource
private PlanSubMapper planSubMapper;
@Resource
private ProcessDesignMapper processDesignMapper;
@Override
public Long createPlanSubDetail(PlanSubDetailSaveReqVO createReqVO) {
@ -71,11 +81,10 @@ public class PlanSubDetailServiceImpl implements PlanSubDetailService {
PlanSubDetailDO planSubDetailDO = planSubDetailMapper.selectById(id);
// 获取当前日期时间
LocalDateTime now = LocalDateTime.now();
// 判断 当前时间是否在startTwoDimDate之后
boolean isGreaterThanCurrent = now.isAfter(planSubDetailDO.getStartTwoDimDate());
if (isGreaterThanCurrent) return CommonResult.error(400,"当前日期>开始日期,不允许删除");
if (ObjectUtil.isNotEmpty(planSubDetailDO.getIsOverProcess())&& planSubDetailDO.getIsOverProcess()==1&&planSubDetailDO.getSeqNo()==1){
if (ObjectUtil.isNotEmpty(planSubDetailDO.getIsOverProcess()) && planSubDetailDO.getIsOverProcess() == 2 && planSubDetailDO.getSeqNo()==1){
return CommonResult.error(400,"该设计已报工,不允许删除");
}
LambdaQueryWrapper<PlanSubDetailDO> wrapper = new LambdaQueryWrapper<>();
@ -166,6 +175,73 @@ public class PlanSubDetailServiceImpl implements PlanSubDetailService {
return planSubDetailDOPageResult;
}
@Override
public PageResult<PlanSubDetailDO> getPlanList(PlanSubDetailPageReqVO pageReqVO) {
return planSubDetailMapper.getPlanList(pageReqVO);
}
@Override
public PlanSubDetailDO queryMaxDetail(PlanSubDetailPageReqVO pageReqVO) {
//判断一下
//twoDimOwner是设计责任人
PlanSubDetailDO planSubDetailDO = planSubDetailMapper.selectOne(new LambdaQueryWrapper<PlanSubDetailDO>()
.eq(PlanSubDetailDO::getTwoDimOwner, pageReqVO.getTwoDimOwner())
.in(PlanSubDetailDO::getIsOverProcess,Arrays.asList(0,2))
.ne(PlanSubDetailDO::getProjectId,pageReqVO.getProjectId())
.orderByDesc(PlanSubDetailDO::getTwoDimDate).last("limit 1"));
if (planSubDetailDO != null){
if (pageReqVO.getQueryDate() != null){
//如果日期不为空查询最大日期
Long l = Long.valueOf(pageReqVO.getQueryDate());
Instant instant = Instant.ofEpochMilli(l);
LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
LocalDateTime startDate = localDateTime.with(LocalTime.MIN);
LocalDateTime now = LocalDateTime.now();
now = now.with(LocalTime.MIN);
//比较一下日期哪个大
if (planSubDetailDO.getTwoDimDate().compareTo(startDate) > 0){
startDate = planSubDetailDO.getTwoDimDate();
}
if (now.compareTo(startDate)>0){
startDate = now;
}
ShopCalendarDO maxShopCalendar = shopCalendarMapper.selectOne(new LambdaQueryWrapper<ShopCalendarDO>().ge(ShopCalendarDO::getDates, startDate)
.eq(ShopCalendarDO::getIfjiejiari, "false").orderByAsc(ShopCalendarDO::getDates).last("limit 1"));
if (maxShopCalendar != null){
planSubDetailDO.setMaxTime(maxShopCalendar.getDates());
}else{
planSubDetailDO.setMaxTime(startDate.plusDays(1));
}
}else{
planSubDetailDO.setMaxTime(planSubDetailDO.getTwoDimDate().plusDays(1));
}
}else{
if (pageReqVO.getQueryDate() != null){
PlanSubDetailDO planSubDetailDO1 = new PlanSubDetailDO();
//如果日期不为空查询最大日期
Long l = Long.valueOf(pageReqVO.getQueryDate());
Instant instant = Instant.ofEpochMilli(l);
LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
LocalDateTime startDate = localDateTime.with(LocalTime.MIN);
LocalDateTime now = LocalDateTime.now();
now = now.with(LocalTime.MIN);
if (now.compareTo(startDate)>0){
startDate = now;
}
ShopCalendarDO maxShopCalendar = shopCalendarMapper.selectOne(new LambdaQueryWrapper<ShopCalendarDO>().ge(ShopCalendarDO::getDates, startDate)
.eq(ShopCalendarDO::getIfjiejiari, "false").orderByAsc(ShopCalendarDO::getDates).last("limit 1"));
if (maxShopCalendar != null){
planSubDetailDO1.setMaxTime(maxShopCalendar.getDates());
}else{
planSubDetailDO1.setMaxTime(startDate.plusDays(1));
}
planSubDetailDO = planSubDetailDO1;
}
}
return planSubDetailDO;
}
@Override
public Integer getSearchRlTs(String startDateTime) {
List<ShopCalendarDO> shopCalendarDOS =shopCalendarMapper.getSearchRlT(startDateTime);
@ -194,7 +270,7 @@ public class PlanSubDetailServiceImpl implements PlanSubDetailService {
LocalDateTime existStart = planSubDetailDO.getStartTwoDimDate();
LocalDateTime existEnd = planSubDetailDO.getTwoDimDate();
// 判断请求时间段是否与已有时间段有重叠
boolean hasOverlap = !reqEnd.isBefore(existStart) && !reqStart.isAfter(existEnd);
boolean hasOverlap = !(reqEnd.compareTo(existStart) < 0) && !(reqStart.compareTo(existEnd) > 0);
if (hasOverlap) {
return CommonResult.error(400, "该子项目设计时间存在交叉,请确认!");
}
@ -205,18 +281,27 @@ public class PlanSubDetailServiceImpl implements PlanSubDetailService {
wrapper1.eq(PlanSubDetailDO::getProjectSubId,updateReqVO.getProjectSubId());
wrapper1.eq(PlanSubDetailDO::getSubType,updateReqVO.getSubType());
String type="BLUEPRINT_WORKBLANK".equals(updateReqVO.getSubType())?"毛坯":"BLUEPRINT_2D".equals(updateReqVO.getSubType())?"2D":"3D";
if (planSubDetailMapper.selectCount(wrapper1)>0) return CommonResult.error(400,"该子项目"+updateReqVO.getName()+" 设计类型"+type+" 存在派工数据,请确认!");
if (planSubDetailMapper.selectCount(wrapper1)> 0 ) return CommonResult.error(400,"该子项目"+updateReqVO.getName()+" 设计类型"+type+" 存在派工数据,请确认!");
}
LambdaQueryWrapper<PlanSubDetailDO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.in(PlanSubDetailDO::getIsOverProcess,0,2);
lambdaQueryWrapper.eq(PlanSubDetailDO::getTwoDimOwner,updateReqVO.getTwoDimOwner());
lambdaQueryWrapper.ge(PlanSubDetailDO::getStartTwoDimDate,updateReqVO.getStartTwoDimDate());
lambdaQueryWrapper.ge(PlanSubDetailDO::getTwoDimDate,updateReqVO.getStartTwoDimDate());
lambdaQueryWrapper.orderByAsc(PlanSubDetailDO::getStartTwoDimDate);
if (ObjectUtil.isNotEmpty(updateReqVO.getId())){
lambdaQueryWrapper.ne(PlanSubDetailDO::getId,updateReqVO.getId());
}
// if (ObjectUtil.isNotEmpty(updateReqVO.getId())){
// lambdaQueryWrapper.ne(PlanSubDetailDO::getId,updateReqVO.getId());
// }
List<PlanSubDetailDO> list = planSubDetailMapper.selectList(lambdaQueryWrapper);
if (ObjectUtil.isEmpty( list) ||updateReqVO.getTwoDimDate().isBefore(list.get(0).getStartTwoDimDate())){
List<PlanSubDetailDO> noSelfList = new ArrayList<>();
for (PlanSubDetailDO planSubDetailDO : list) {
if (!planSubDetailDO.getId().equals(updateReqVO.getId())){
noSelfList.add(planSubDetailDO);
}
}
if (ObjectUtil.isEmpty( noSelfList) && ((updateReqVO.getStartTwoDimDate().compareTo(noSelfList.get(0).getTwoDimDate()) <=0 )&& (updateReqVO.getTwoDimDate().compareTo(noSelfList.get(0).getStartTwoDimDate()) >= 0))){
if (ObjectUtil.isNotEmpty(updateReqVO.getId())){
planSubDetailMapper.delete(PlanSubDetailDO::getId,updateReqVO.getId());
}
@ -233,12 +318,495 @@ public class PlanSubDetailServiceImpl implements PlanSubDetailService {
planSubDetailDO.setSeqNo(1L);
planSubDetailDO.setDesignNum(updateReqVO.getDesignNum());
planSubDetailDO.setCode(updateReqVO.getCode());
list.add(planSubDetailDO);
list.sort(Comparator.comparing(PlanSubDetailDO::getStartTwoDimDate, Comparator.nullsLast(Comparator.naturalOrder())));
for (int i = 0; i < list.size(); i++) {
list.get(i).setSeqNo(Long.valueOf(i + 1)); // 设置顺序为 1, 2, 3
}
planSubDetailMapper.insertOrUpdateBatch(list);
return CommonResult.success(true);
}
updateReqVO.setList( list);
return CommonResult.success(updateReqVO);
}
@Override
public CommonResult operate(PlanSubDetailSaveReqVO updateReqVO) {
List<PlanSubDetailDO> list = updateReqVO.getList();
HashSet<Long> ownerSet = new HashSet<>();
for (PlanSubDetailDO planSubDetailDO : list) {
if (planSubDetailDO.getId() == null){
String type="BLUEPRINT_WORKBLANK".equals(planSubDetailDO.getSubType())?"毛坯":"BLUEPRINT_2D".equals(planSubDetailDO.getSubType())?"2D":"3D";
//该项目名称+子项目名称+类型没有保存请先修改
return CommonResult.error(400, "该子项目"+planSubDetailDO.getName()+" 设计类型"+type+" ,没有保存请确认!");
}else {
planSubDetailDO.setDesignNum(calculateWorkDays(planSubDetailDO.getStartTwoDimDate(),planSubDetailDO.getTwoDimDate()));
ownerSet.add(planSubDetailDO.getTwoDimOwner());
}
}
if (ownerSet.size() > 1){
return CommonResult.error(400, "项目存在多个负责人,不允许保存。请单条修改!");
}
for (PlanSubDetailDO planSubDetailDO : list) {
for (PlanSubDetailDO subDetailDO : list) {
if(!planSubDetailDO.getId().equals(subDetailDO.getId())){
//判断时间交叉
LocalDateTime reqStart = subDetailDO.getStartTwoDimDate();
LocalDateTime reqEnd = subDetailDO.getTwoDimDate();
LocalDateTime existStart = planSubDetailDO.getStartTwoDimDate();
LocalDateTime existEnd = planSubDetailDO.getTwoDimDate();
// 判断请求时间段是否与已有时间段有重叠
boolean hasOverlap = !(reqEnd.compareTo(existStart) < 0) && !(reqStart.compareTo(existEnd) > 0);
if (hasOverlap) {
return CommonResult.error(400, "该子项目设计时间存在交叉,请确认!");
}
}
}
}
planSubDetailMapper.updateBatch(list);
//更新表pro_process_design
Map<Long, List<PlanSubDetailDO>> collect = list.stream().collect(Collectors.groupingBy(PlanSubDetailDO::getProjectPlanSubId));
return CommonResult.success(true);
}
@Override
@Transactional
public CommonResult savechahuoList(PlanSubDetailSaveReqVO updateReqVO){
List<PlanSubDetailDO> list = updateReqVO.getList();
list.sort(Comparator.comparing(PlanSubDetailDO::getStartTwoDimDate, Comparator.nullsLast(Comparator.naturalOrder())));
Map<Long, List<PlanSubDetailDO>> collect = list.stream().filter(item -> item.getId() != null ).collect(Collectors.groupingBy(PlanSubDetailDO::getId));
HashSet<Long> deleteId = new HashSet<>();
for (Long id : collect.keySet()) {
List<PlanSubDetailDO> planSubDetailDOS = collect.get(id);
if (collect.get(id).size() > 1){
deleteId.add(id);
for (PlanSubDetailDO planSubDetailDO : collect.get(id)) {
planSubDetailDO.setId(null);
}
}
}
Map<Long, List<PlanSubDetailDO>> collect1 = list.stream().collect(Collectors.groupingBy(PlanSubDetailDO::getProjectSubId));
collect1.forEach((id,detailList) -> {
Map<String, List<PlanSubDetailDO>> collect2 = detailList.stream().collect(Collectors.groupingBy(PlanSubDetailDO::getSubType));
collect2.forEach((type,list2) ->{
int i = 1;
for (PlanSubDetailDO planSubDetailDO : list2) {
planSubDetailDO.setSeqNo(Long.valueOf(i++));
}
});
});
planSubDetailMapper.deleteBatchIds(deleteId);
planSubDetailMapper.insertOrUpdateBatch(list);
return CommonResult.success(true);
}
@Override
@Transactional
public CommonResult chahuoList(PlanSubDetailSaveReqVO updateReqVO) {
List<PlanSubDetailDO> list = updateReqVO.getList();
if (CollUtil.isEmpty(list)) {
return CommonResult.error(400, "列表为空,请刷新页面后重试!");
}
// 1. 拿到整个list最大的twoDimDate时间
LocalDateTime minDate = list.stream()
.map(PlanSubDetailDO::getStartTwoDimDate)
.min(LocalDateTime::compareTo)
.orElse(null);
LocalDateTime maxDate = list.stream()
.map(PlanSubDetailDO::getTwoDimDate)
.max(LocalDateTime::compareTo)
.orElse(null);
// 2. 查询最大时间往后90天内的节假日
LocalDateTime endDate = maxDate.plusDays(90);
List<ShopCalendarDO> shopCalendarDOList = shopCalendarMapper.selectList(new LambdaQueryWrapper<ShopCalendarDO>().eq(ShopCalendarDO::getIfjiejiari, "true")
.between(ShopCalendarDO::getDates, minDate, endDate).orderByAsc(ShopCalendarDO::getDates));
List<LocalDateTime> holidayList = new ArrayList<>();
for (ShopCalendarDO shopCalendarDO : shopCalendarDOList) {
holidayList.add(shopCalendarDO.getDates());
}
// 3. 将id为空的数据拿出来进行插活
List<PlanSubDetailDO> insertList = list.stream()
.filter(item -> item.getId() == null)
.collect(Collectors.toList());
for (PlanSubDetailDO planSubDetailDO : insertList) {
planSubDetailDO.setIsCha("Y");
}
// 4. 将id不为空的按startTwoDimDate进行升序排序形成baseList
List<PlanSubDetailDO> baseList = list.stream()
.filter(item -> item.getId() != null)
.sorted(Comparator.comparing(PlanSubDetailDO::getStartTwoDimDate))
.collect(Collectors.toList());
// 5. 执行插活逻辑
List<PlanSubDetailDO> resultList = performInsertLogic(baseList, insertList, holidayList);
// 6. 保存结果
updateReqVO.setList(resultList);
return CommonResult.success(updateReqVO);
}
/**
* 执行插活逻辑
*/
private List<PlanSubDetailDO> performInsertLogic(List<PlanSubDetailDO> baseList,
List<PlanSubDetailDO> insertList,
List<LocalDateTime> holidayList) {
List<PlanSubDetailDO> resultList = new ArrayList<>();
// 1. 先处理插活数据按节假日分段
List<PlanSubDetailDO> processedInsertList = new ArrayList<>();
for (PlanSubDetailDO insertItem : insertList) {
LocalDateTime startDate = insertItem.getStartTwoDimDate();
LocalDateTime endDate = insertItem.getTwoDimDate();
// 检查该时间段内是否有节假日
List<LocalDateTime> holidaysInRange = getHolidaysInRange(startDate, endDate, holidayList);
if (holidaysInRange.isEmpty()) {
// 没有节假日直接添加
processedInsertList.add(insertItem);
} else {
// 有节假日需要分段处理
List<PlanSubDetailDO> segments = splitByHolidays(insertItem, holidaysInRange);
processedInsertList.addAll(segments);
}
}
// 2. 如果没有插活数据直接返回baseList
if (processedInsertList.isEmpty()) {
return new ArrayList<>(baseList);
}
// 3. 获取插活数据的开始时间
LocalDateTime insertStartTime = processedInsertList.stream()
.map(PlanSubDetailDO::getStartTwoDimDate)
.min(LocalDateTime::compareTo)
.orElse(null);
// 4. 分离baseList在插活数据之前的被打断的在插活数据之后的
List<PlanSubDetailDO> beforeInsertList = new ArrayList<>();
List<PlanSubDetailDO> interruptedList = new ArrayList<>();
List<PlanSubDetailDO> afterInsertList = new ArrayList<>();
List<PlanSubDetailDO> remainingBaseList = new ArrayList<>();
if (insertStartTime != null) {
for (PlanSubDetailDO baseItem : baseList) {
if (baseItem.getTwoDimDate().isBefore(insertStartTime)) {
// 完全在插活数据之前
beforeInsertList.add(baseItem);
} else if (baseItem.getStartTwoDimDate().isBefore(insertStartTime) &&
baseItem.getTwoDimDate().isAfter(insertStartTime.minusDays(1))) {
// 被插活数据打断
interruptedList.add(baseItem);
} else {
// 在插活数据之后
afterInsertList.add(baseItem);
}
}
} else {
beforeInsertList.addAll(baseList);
}
// 5. 处理插活数据之前的baseList保持原样
resultList.addAll(beforeInsertList);
// 6. 处理被打断的baseList
for (PlanSubDetailDO interruptedItem : interruptedList) {
// 计算插活数据开始前的天数
long daysBeforeInsert = ChronoUnit.DAYS.between(interruptedItem.getStartTwoDimDate(), insertStartTime);
if (daysBeforeInsert > 0) {
// 创建插活前的段落
LocalDateTime segmentEnd = interruptedItem.getStartTwoDimDate().plusDays(daysBeforeInsert - 1);
PlanSubDetailDO beforeSegment = createBaseItem(interruptedItem, interruptedItem.getStartTwoDimDate(), segmentEnd);
beforeSegment.setDesignNum(daysBeforeInsert);
resultList.add(beforeSegment);
// 保存剩余的designNum
Long remainingDesignNum = interruptedItem.getDesignNum() - daysBeforeInsert;
if (remainingDesignNum > 0) {
// 创建剩余的baseItem稍后处理
PlanSubDetailDO remainingItem = new PlanSubDetailDO();
// 复制属性
remainingItem.setId(interruptedItem.getId());
remainingItem.setProjectPlanId(interruptedItem.getProjectPlanId());
remainingItem.setProjectId(interruptedItem.getProjectId());
remainingItem.setProjectPlanSubId(interruptedItem.getProjectPlanSubId());
remainingItem.setProjectSubCode(interruptedItem.getProjectSubCode());
remainingItem.setTwoDimOwner(interruptedItem.getTwoDimOwner());
remainingItem.setProjectSubId(interruptedItem.getProjectSubId());
remainingItem.setSubType(interruptedItem.getSubType());
remainingItem.setName(interruptedItem.getName());
remainingItem.setCode(interruptedItem.getCode());
remainingItem.setDesignNum(remainingDesignNum);
remainingBaseList.add(remainingItem);
}
} else {
// 整个被打断全部加入剩余列表
remainingBaseList.add(interruptedItem);
}
}
// 7. 添加插活数据
resultList.addAll(processedInsertList);
// 8. 处理剩余的baseList被打断的剩余部分 + 原本在插活数据之后的
List<PlanSubDetailDO> allRemainingList = new ArrayList<>();
allRemainingList.addAll(remainingBaseList);
allRemainingList.addAll(afterInsertList);
if (!allRemainingList.isEmpty()) {
// 获取插活数据的最后结束时间
LocalDateTime lastInsertEndTime = processedInsertList.stream()
.map(PlanSubDetailDO::getTwoDimDate)
.max(LocalDateTime::compareTo)
.orElse(null);
// 从插活数据的下一天开始顺延
LocalDateTime baseStartTime = lastInsertEndTime.plusDays(1);
for (PlanSubDetailDO baseItem : allRemainingList) {
// 按照原有的designNum计算新的时间段
LocalDateTime newStartTime = baseStartTime;
LocalDateTime newEndTime = newStartTime.plusDays(baseItem.getDesignNum() - 1);
// 检查新的时间段内是否有节假日
List<LocalDateTime> holidaysInRange = getHolidaysInRange(newStartTime, newEndTime, holidayList);
if (holidaysInRange.isEmpty()) {
// 没有节假日直接添加
PlanSubDetailDO newBaseItem = createBaseItem(baseItem, newStartTime, newEndTime);
resultList.add(newBaseItem);
baseStartTime = newEndTime.plusDays(1);
} else {
// 有节假日需要分段处理
List<PlanSubDetailDO> segments = splitBaseItemByHolidays(baseItem, newStartTime, newEndTime, holidaysInRange);
resultList.addAll(segments);
// 更新下一个baseItem的开始时间
LocalDateTime lastSegmentEndTime = segments.stream()
.map(PlanSubDetailDO::getTwoDimDate)
.max(LocalDateTime::compareTo)
.orElse(newEndTime);
baseStartTime = lastSegmentEndTime.plusDays(1);
}
}
}
// 9. 按开始时间排序
resultList.sort(Comparator.comparing(PlanSubDetailDO::getStartTwoDimDate));
return resultList;
}
private List<PlanSubDetailDO> splitByHolidays(PlanSubDetailDO original, List<LocalDateTime> holidaysInRange) {
List<PlanSubDetailDO> segments = new ArrayList<>();
LocalDateTime currentStart = original.getStartTwoDimDate();
LocalDateTime originalEnd = original.getTwoDimDate();
for (LocalDateTime holiday : holidaysInRange) {
// 修复只有当currentStart在节假日前时才创建节假日前的一段
if (currentStart.isBefore(holiday)) {
LocalDateTime segmentEnd = holiday.minusDays(1);
if (currentStart.isBefore(segmentEnd) || currentStart.isEqual(segmentEnd)) {
// 节假日前的段落
PlanSubDetailDO beforeHoliday = createSegment(original, currentStart, segmentEnd);
segments.add(beforeHoliday);
}
}
// 跳过节假日从节假日后一天开始
currentStart = holiday.plusDays(1);
}
// 最后一段确保还有剩余时间
if (!currentStart.isAfter(originalEnd)) {
PlanSubDetailDO lastSegment = createSegment(original, currentStart, originalEnd);
segments.add(lastSegment);
}
return segments;
}
/**
* 按节假日分段带时间控制用于插活数据
*/
private List<PlanSubDetailDO> splitByHolidaysWithTime(PlanSubDetailDO original,
LocalDateTime startTime,
LocalDateTime endTime,
List<LocalDateTime> holidaysInRange) {
List<PlanSubDetailDO> segments = new ArrayList<>();
LocalDateTime currentStart = startTime;
for (LocalDateTime holiday : holidaysInRange) {
if (currentStart.isBefore(holiday)) {
LocalDateTime segmentEnd = holiday.minusDays(1);
if (currentStart.isBefore(segmentEnd) || currentStart.isEqual(segmentEnd)) {
PlanSubDetailDO beforeHoliday = createSegment(original, currentStart, segmentEnd);
segments.add(beforeHoliday);
}
}
currentStart = holiday.plusDays(1);
}
// 最后一段
if (!currentStart.isAfter(endTime)) {
PlanSubDetailDO lastSegment = createSegment(original, currentStart, endTime);
segments.add(lastSegment);
}
return segments;
}
private List<PlanSubDetailDO> splitBaseItemByHolidays(PlanSubDetailDO original,
LocalDateTime startTime,
LocalDateTime endTime,
List<LocalDateTime> holidaysInRange) {
List<PlanSubDetailDO> segments = new ArrayList<>();
LocalDateTime currentStart = startTime;
Long totalDesignNum = original.getDesignNum();
Long usedDesignNum = 0L;
for (LocalDateTime holiday : holidaysInRange) {
if (currentStart.isBefore(holiday)) {
// 计算到节假日前一天的天数
long daysToHoliday = ChronoUnit.DAYS.between(currentStart, holiday);
if (daysToHoliday > 0) {
long segmentDays = Math.min(daysToHoliday, totalDesignNum - usedDesignNum);
if (segmentDays > 0) {
// 节假日前的段落
LocalDateTime segmentEnd = currentStart.plusDays(segmentDays - 1);
PlanSubDetailDO beforeHoliday = createBaseItem(original, currentStart, segmentEnd);
beforeHoliday.setDesignNum(segmentDays); // 设置实际的designNum
segments.add(beforeHoliday);
usedDesignNum += segmentDays;
currentStart = holiday.plusDays(1);
}
} else {
currentStart = holiday.plusDays(1);
}
// 如果已经用完了designNum直接返回
if (usedDesignNum >= totalDesignNum) {
return segments;
}
} else {
currentStart = holiday.plusDays(1);
}
}
// 最后一段
if (usedDesignNum < totalDesignNum) {
long remainingDays = totalDesignNum - usedDesignNum;
LocalDateTime lastSegmentEnd = currentStart.plusDays(remainingDays - 1);
PlanSubDetailDO lastSegment = createBaseItem(original, currentStart, lastSegmentEnd);
lastSegment.setDesignNum(remainingDays); // 设置实际的designNum
segments.add(lastSegment);
}
return segments;
}
/**
* 创建分段对象用于插活数据
*/
private PlanSubDetailDO createSegment(PlanSubDetailDO original, LocalDateTime startDate, LocalDateTime endDate) {
PlanSubDetailDO segment = new PlanSubDetailDO();
segment.setId(null); // 新分段id为空
segment.setProjectPlanId(original.getProjectPlanId());
segment.setProjectId(original.getProjectId());
segment.setProjectPlanSubId(original.getId());
segment.setProjectSubCode(original.getProjectSubCode());
segment.setTwoDimOwner(Long.valueOf(original.getTwoDimOwner()));
segment.setProjectSubId(original.getProjectSubId());
segment.setSubType(original.getSubType());
segment.setName(original.getName());
segment.setCode(original.getCode());
segment.setStartTwoDimDate(startDate);
segment.setTwoDimDate(endDate);
// 只有id为空的才重新计算designNum
segment.setDesignNum(calculateWorkDays(startDate, endDate));
return segment;
}
/**
* 创建baseItem对象用于baseList顺延
*/
private PlanSubDetailDO createBaseItem(PlanSubDetailDO original, LocalDateTime startDate, LocalDateTime endDate) {
PlanSubDetailDO baseItem = new PlanSubDetailDO();
// 复制原有属性
baseItem.setId(original.getId());
baseItem.setProjectPlanId(original.getProjectPlanId());
baseItem.setProjectId(original.getProjectId());
baseItem.setProjectPlanSubId(original.getProjectPlanSubId());
baseItem.setProjectSubCode(original.getProjectSubCode());
baseItem.setTwoDimOwner(original.getTwoDimOwner());
baseItem.setProjectSubId(original.getProjectSubId());
baseItem.setSubType(original.getSubType());
baseItem.setName(original.getName());
baseItem.setCode(original.getCode());
baseItem.setDesignNum(calculateWorkDays(startDate, endDate));
baseItem.setStartTwoDimDate(startDate);
baseItem.setTwoDimDate(endDate);
return baseItem;
}
/**
* 获取时间段内的节假日
*/
private List<LocalDateTime> getHolidaysInRange(LocalDateTime startDate, LocalDateTime endDate,
List<LocalDateTime> holidayList) {
return holidayList.stream()
.filter(holiday -> !holiday.isBefore(startDate) && !holiday.isAfter(endDate))
.sorted()
.collect(Collectors.toList());
}
/**
* 计算工作天数排除节假日
*/
private Long calculateWorkDays(LocalDateTime startDate, LocalDateTime endDate) {
long workDays = 0;
LocalDateTime current = startDate.toLocalDate().atStartOfDay();
LocalDateTime end = endDate.toLocalDate().atStartOfDay();
while (!current.isAfter(end)) {
// 检查是否是工作日
workDays++;
current = current.plusDays(1);
}
return workDays;
}
/**
* 保存计划子明细
*/
private void savePlanSubDetails(List<PlanSubDetailDO> resultList) {
for (PlanSubDetailDO item : resultList) {
if (item.getId() == null) {
// 新增
planSubDetailMapper.insert(item);
} else {
// 更新
planSubDetailMapper.updateById(item);
}
}
}
@Override
public CommonResult insertWork(PlanSubDetailSaveReqVO updateReqVO) {
List<PlanSubDetailDO> list = updateReqVO.getList();

View File

@ -676,7 +676,7 @@ public class ProcessBomServiceImpl implements ProcessBomService {
// if(vo.getMemo()!=null){
// vo.setMemo(vo.getMemo()+"→物料名称由"+po.getMaterialName()+"变为"+vo.getMaterialName());
// }else{
change = true;
change = true;
changeContent += "→物料名称由"+po.getMaterialName()+"变为"+vo.getMaterialName();
// }
}

View File

@ -14,7 +14,7 @@ public interface ShopCalendarService {
* @return 物料
*/
PageResult<ShopCalendarDO> searchRl(ShopCalendarPageReqVO shopCalendarPageReqVO);
Boolean searchHoliday(ShopCalendarPageReqVO shopCalendarPageReqVO);
Boolean insert(String dates);
Boolean updateRl(String ifjiejiari,String dates,String times);

View File

@ -1,7 +1,11 @@
package com.chanko.yunxi.mes.module.heli.service.shopCalendar;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.chanko.yunxi.mes.framework.common.pojo.PageResult;
import com.chanko.yunxi.mes.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.chanko.yunxi.mes.module.heli.controller.admin.shopCalendar.vo.ShopCalendarPageReqVO;
import com.chanko.yunxi.mes.module.heli.dal.dataobject.shopCalendar.ShopCalendarDO;
import com.chanko.yunxi.mes.module.heli.dal.mysql.shopCalendar.ShopCalendarMapper;
@ -9,9 +13,7 @@ import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.format.TextStyle;
import java.util.*;
@ -40,6 +42,21 @@ public class ShopCalendarServiceImpl implements ShopCalendarService {
return shopCalendarMapper.searchRl(shopCalendarPageReqVO);
}
@Override
public Boolean searchHoliday(ShopCalendarPageReqVO shopCalendarPageReqVO) {
String queryDate = shopCalendarPageReqVO.getQueryDate();
Long l = Long.valueOf(queryDate);
Instant instant = Instant.ofEpochMilli(l);
LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
LocalDateTime startDate = localDateTime.with(LocalTime.MIN);
List<ShopCalendarDO> aTrue = shopCalendarMapper.selectList(new LambdaQueryWrapperX<ShopCalendarDO>().eq(ShopCalendarDO::getDates, startDate).eq(ShopCalendarDO::getIfjiejiari, "true"));
if (CollUtil.isNotEmpty(aTrue)){
return false;
}else {
return true;
}
}
/*重置当月节假日*/
@Override

View File

@ -1,4 +1,4 @@
// const devBaseURL = 'http://localhost:5281'
const devBaseURL = 'http://localhost:8080'
// const devBaseURL = 'http://5a35a48943.wicp.vip:40709'
// const proBaseURL = 'http://5a35a48943.wicp.vip:40709'
// const devBaseURL = 'http://124.221.23.100:9003'
@ -7,8 +7,8 @@
// const proBaseURL = 'http://118.195.155.9:9002/'
// const devBaseURL = 'http://192.168.0.169:9002/'
// const proBaseURL = 'http://192.168.0.169:9002/'
const devBaseURL = 'http://218.75.46.166:8889/'
const proBaseURL = 'http://218.75.46.166:8889/'
// const devBaseURL = 'http://218.75.46.166:8889/'
// const proBaseURL = 'http://218.75.46.166:8889/'
export const BASE_URL = process.env.NODE_ENV === 'development' ? devBaseURL : proBaseURL
export const TIMEOUT = 5000

View File

@ -28,6 +28,13 @@ export const getPlanSub = async (id: number) => {
return await request.get({ url: `/heli/plan-sub/get?id=` + id })
}
export const operate = async (data) => {
return await request.post({ url: `/heli/plan-sub/operate`, data })
}
//插活保存
export const getOwnderPlanChaHuo = async (data) => {
//return await request.post({ url: `/heli/plan-sub/postOwnderChaHuo`,data})

View File

@ -22,6 +22,13 @@ export const getPlanSubDetailPage = async (params) => {
return await request.get({ url: `/heli/plan-sub-detail/page`, params })
}
export const pageAddList = async (params) => {
return await request.get({ url: `/heli/plan-sub-detail/pageAddList`, params })
}
export const queryMaxDetail = async (params) => {
return await request.get({ url: `/heli/plan-sub-detail/queryMaxDetail`, params })
}
// 查询生产计划子项目设计时间明细详情
export const getPlanSubDetail = async (id: number) => {
return await request.get({ url: `/heli/plan-sub-detail/get?id=` + id })
@ -36,7 +43,20 @@ export const createPlanSubDetail = async (data: PlanSubDetailVO) => {
export const updatePlanSubDetail = async (data: PlanSubDetailVO) => {
return await request.put({ url: `/heli/plan-sub-detail/update`, data })
}
export const modificationPlanSubDetail = async (data: PlanSubDetailVO) => {
return await request.post({ url: `/heli/plan-sub-detail/modification`, data })
}
export const chahuoPlanSubDetail = async (data) => {
return await request.post({ url: `/heli/plan-sub-detail/chahuo`, data })
}
export const savechahuoPlanSubDetail = async (data) => {
return await request.post({ url: `/heli/plan-sub-detail/savechahuo`, data })
}
export const operate = async (data) => {
return await request.post({ url: `/heli/plan-sub-detail/operate`, data })
}
// 删除生产计划子项目设计时间明细
export const deletePlanSubDetail = async (id: number) => {
return await request.delete({ url: `/heli/plan-sub-detail/delete?id=` + id })

View File

@ -12,7 +12,10 @@ export interface ShopCalendarVO {
export const getShopCalendarPage = async (params) => {
return await request.get({ url: `/heli/shopCalendar/searchRl`, params })
}
// 查询日历
export const isHoliday= async (params) => {
return await request.get({ url: `/heli/shopCalendar/searchHoliday`, params })
}
// 新增日历
export const createShopCalendarPlan = async (dates: string) => {
return await request.post({ url: `/heli/shopCalendar/insert?dates=` + dates })

View File

@ -106,7 +106,7 @@
<span>制单人{{ `` }}</span>
<span>-客户联-</span>
</div>
<div class="divide_line" style="margin: 20px 0"></div>
<div class="divide_line" style="margin: 10px 0"></div>
<!-- 回单联 -->
<table border="2" cellspacing="0" id="table1" style="position: relative !important">
<!-- <img

View File

@ -46,13 +46,10 @@ const gitlist = async () => {
userList.value = []
userSelectList.value = []
userList.value = [...userList.value, ...data.list]
console.log(propsmodelValue.value)
//
if (propsmodelValue.value) {
valueName.value = propsmodelValue.value
const initialUser = await UserApi.getUser(valueName.value)
console.log(valueName.value)
console.log(initialUser)
if (initialUser){
if (initialUser.status == 1) {
status1.value = true

View File

@ -13,22 +13,25 @@
label-width="110px"
>
<el-form-item label="负责人" prop="twoDimOwner">
<el-select class="!w-265px" v-model="queryParams.twoDimOwner" clearable filterable>
<el-select class="!w-265px" v-model="queryParams.twoDimOwner" clearable filterable>
<el-option
v-for="dict in userInit" :key="dict.id"
:label="dict.nickname" :value="dict.id" />
v-for="dict in userInit"
:key="dict.id"
:label="dict.nickname"
:value="dict.id"
/>
</el-select>
</el-form-item>
<el-form-item label="开始日期" prop="startTime">
<el-date-picker
v-model="queryParams.startTime"
value-format="YYYY-MM-DD"
type="daterange"
start-placeholder="开始日期"
end-placeholder="结束日期"
class="!w-280px"
/>
</el-form-item>
<el-form-item label="开始日期" prop="beginTime">
<el-date-picker
v-model="queryParams.beginTime"
value-format="YYYY-MM-DD"
type="date"
start-placeholder="开始日期"
end-placeholder="结束日期"
class="!w-280px"
/>
</el-form-item>
<el-form-item label="项目编号" prop="code">
<el-input
v-model="queryParams.code"
@ -50,86 +53,120 @@
<el-form-item label="设计类型" prop="subType">
<el-select v-model="queryParams.subType" placeholder="类型" clearable class="!w-240px">
<el-option v-for="dict in getIntDictOptions(DICT_TYPE.HELI_CH_PROCESS_TYPE)" :key="dict.value" :label="dict.label" :value="dict.value" />
<el-option
v-for="dict in getStrDictOptions(DICT_TYPE.HELI_CH_PROCESS_TYPE)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery" type="primary"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="handleQuery" type="primary"
><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button
>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
<el-button @click="saveForm" type="warning">保存</el-button>
<el-button @click="addForm" type="success">新增</el-button>
</el-form-item>
</el-form>
</ContentWrap>
<!-- 列表 -->
<ContentWrap>
<el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" class="hl-table" border>
<el-table
v-loading="loading"
:data="list"
:show-overflow-tooltip="true"
class="hl-table"
border
>
<el-table-column fixed label="序号" type="index" width="70" align="center" />
<el-table-column fixed label="项目编码" align="center" prop="code" min-width="120" />
<el-table-column fixed label="子项目名称" align="center" prop="name" min-width="250" />
<el-table-column min-width="200px" align="center" >
<el-table-column min-width="200px" align="center">
<template #header>设计类型</template>
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.subType`" class="mb-0px!" >
<el-select class="!w-265px" v-model="row.subType" clearable filterable :disabled="row.flag==0">
<el-form-item :prop="`${$index}.subType`" class="mb-0px!">
<el-select class="!w-265px" v-model="row.subType" clearable filterable :disabled="row.userFlag == false">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.HELI_CH_PROCESS_TYPE)" :key="dict.value"
:label="dict.label" :value="dict.value" />
v-for="dict in getStrDictOptions(DICT_TYPE.HELI_CH_PROCESS_TYPE)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
</template>
</el-table-column>
<el-table-column min-width="200px" align="center" >
<template #header>负责人</template>
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.twoDimOwner`" class="mb-0px!" >
<el-select class="!w-265px" v-model="row.twoDimOwner" clearable filterable :disabled="row.flag==0">
<el-option
v-for="dict in userInit" :key="dict.id"
:label="dict.username+' '+dict.nickname" :value="dict.id" />
</el-select>
</el-form-item>
</template>
</el-table-column>
<el-table-column min-width="200px" align="center" >
<el-table-column min-width="200px" align="center">
<template #header>负责人</template>
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.twoDimOwner`" class="mb-0px!">
<el-select
class="!w-265px"
v-model="row.twoDimOwner"
clearable
filterable
:disabled="row.flag == 0 "
>
<el-option
v-for="dict in userInit"
:key="dict.id"
:label="dict.username + ' ' + dict.nickname"
:value="dict.id"
/>
</el-select>
</el-form-item>
</template>
</el-table-column>
<el-table-column min-width="200px" align="center">
<template #header>开始日期</template>
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.startTwoDimDate`" class="mb-0px!" >
<el-date-picker class="!w-265px" v-model="row.startTwoDimDate" type="date" @change="change1(row,0)" value-format="x" placeholder="开始日期" :disabled="row.flag==0" :disabled-date="disabledFutureDates"
<el-form-item :prop="`${$index}.startTwoDimDate`" class="mb-0px!">
<el-date-picker
class="!w-265px"
v-model="row.startTwoDimDate"
type="date"
@change="change1(row, 0)"
value-format="x"
placeholder="开始日期"
:disabled="row.flag == 0 "
:disabled-date="disabledFutureDates"
/>
</el-form-item>
</template>
</el-table-column>
<el-table-column min-width="200px" align="center" >
<el-table-column min-width="200px" align="center">
<template #header>结束日期</template>
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.twoDimDate`" class="mb-0px!" >
<el-date-picker class="!w-265px" v-model="row.twoDimDate" type="date" @change="change1(row,1)" value-format="x" placeholder="结束日期" :disabled="row.flag==0" :disabled-date="disabledFutureDates"/>
<el-form-item :prop="`${$index}.twoDimDate`" class="mb-0px!">
<el-date-picker
class="!w-265px"
v-model="row.twoDimDate"
type="date"
@change="change1(row, 1)"
value-format="x"
placeholder="结束日期"
:disabled="row.flag == 0 "
:disabled-date="disabledFutureDates"
/>
</el-form-item>
</template>
</el-table-column>
<el-table-column label="设计天数" align="center" prop="designNum" min-width="120"/>
<el-table-column label="时间段顺序" align="center" prop="seqNo" min-width="120"/>
<el-table-column label="是否新增" align="center" prop="seqNo" min-width="120">
<el-table-column label="设计天数" align="center" prop="designNum" min-width="120" />
<el-table-column label="时间段顺序" align="center" prop="seqNo" min-width="120" />
<el-table-column label="是否新增" align="center" prop="seqNo" min-width="120">
<template #default="scope">
{{ scope.row.isAdd==1?"是":"否" }}
{{ scope.row.isAdd == 1 ? '是' : '否' }}
</template>
</el-table-column>
<el-table-column label="操作" align="center" fixed="right" min-width="120">
<!-- <template #default="scope">-->
<!-- <el-button link type="primary" @click="modification(scope.row)" >-->
<!-- 修改-->
<!-- </el-button>-->
<!-- <el-button-->
<!-- link-->
<!-- type="danger"-->
<!-- >-->
<!-- 删除-->
<!-- </el-button>-->
<!-- <el-button link type="primary" >-->
<!-- 新增-->
<!-- </el-button>-->
<!-- </template>-->
<el-table-column label="操作" align="center" fixed="right" min-width="190">
<template #default="scope">
<el-button link type="primary" @click="addItemRow(scope.row)"> 新增 </el-button>
<el-button link type="success" @click="modification(scope.row)"> 修改 </el-button>
<el-button link @click="handleDelete(scope.row)" type="danger"> 删除 </el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
@ -141,45 +178,385 @@
/>
</ContentWrap>
</el-card>
<!----插活弹框-->
<!-- 插活弹窗 -->
<el-dialog v-model="dialogVisible" width="80%" :close-on-click-modal="false">
<div class="dialog-content">
<!-- 第一排当前日期信息 -->
<!-- 第二排状态标题 -->
<div class="status-title">
<h3>{{
dialogTitle +
'(当前:' +
formatDate(currentRow?.startTwoDimDate, 'YYYY-MM-DD') +
'至' +
formatDate(currentRow?.twoDimDate, 'YYYY-MM-DD') +
')'
}}</h3>
</div>
<!-- 表格 -->
<el-table
v-loading="loading2"
:data="insertList"
:show-overflow-tooltip="true"
class="hl-table"
border
max-height="400"
>
<el-table-column fixed label="序号" type="index" width="70" align="center" />
<el-table-column fixed label="项目编码" align="center" prop="code" min-width="120" />
<el-table-column fixed label="子项目名称" align="center" prop="name" min-width="250" />
<el-table-column min-width="200px" align="center">
<template #header>设计类型</template>
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.subType`" class="mb-0px!">
<el-select class="!w-265px" v-model="row.subType" clearable filterable disabled>
<el-option
v-for="dict in getStrDictOptions(DICT_TYPE.HELI_CH_PROCESS_TYPE)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
</template>
</el-table-column>
<el-table-column min-width="200px" align="center">
<template #header>负责人</template>
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.twoDimOwner`" class="mb-0px!">
<el-select class="!w-265px" v-model="row.twoDimOwner" clearable filterable disabled>
<el-option
v-for="dict in userInit"
:key="dict.id"
:label="dict.username + ' ' + dict.nickname"
:value="dict.id"
/>
</el-select>
</el-form-item>
</template>
</el-table-column>
<el-table-column min-width="200px" align="center">
<template #header>开始日期</template>
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.startTwoDimDate`" class="mb-0px!">
<el-date-picker
class="!w-265px"
v-model="row.startTwoDimDate"
type="date"
@change="change1(row, 0)"
value-format="x"
placeholder="开始日期"
disabled
:disabled-date="disabledFutureDates"
/>
</el-form-item>
</template>
</el-table-column>
<el-table-column min-width="200px" align="center">
<template #header>结束日期</template>
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.twoDimDate`" class="mb-0px!">
<el-date-picker
class="!w-265px"
v-model="row.twoDimDate"
type="date"
@change="change1(row, 1)"
value-format="x"
placeholder="结束日期"
disabled
:disabled-date="disabledFutureDates"
/>
</el-form-item>
</template>
</el-table-column>
<el-table-column label="设计天数" align="center" prop="designNum" min-width="120" />
</el-table>
</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="handleCancelDialog">取消</el-button>
<el-button v-if="dialogTitle == '插活前'" type="warning" @click="handleInsert"
>插活</el-button
>
<el-button v-else type="primary" @click="handleConfirm">确认</el-button>
</div>
</template>
</el-dialog>
<el-dialog v-model="addDialogVisible" title="新增" width="80%">
<!-- 查询条件 -->
<el-form inline class="mb-4">
<el-form-item label="项目编码">
<el-input v-model="addQueryParams.projectCode" placeholder="请输入项目编码" />
</el-form-item>
<el-form-item label="子项目名称">
<el-input v-model="addQueryParams.projectSubName" placeholder="请输入子项目名称" />
</el-form-item>
<el-button type="primary" @click="handleAddQuery">查询</el-button>
</el-form>
<!-- 新增 -->
<el-table
:data="addList"
v-loading="loading3"
highlight-current-row
ref="multipleTableRef" @select="handlerSelect"
@selection-change="handleSelectionChange"
@row-click="rowClickHandle"
:row-key="row => row.id"
>
<el-table-column type="selection" width="55" />
<el-table-column type="index" label="序号" width="70" align="center" />
<el-table-column prop="projectName" label="项目名称" min-width="180" />
<el-table-column prop="code" label="项目编码" min-width="150" />
<el-table-column prop="name" label="子项目名称" min-width="180" />
<el-table-column prop="customerBrief" label="客户简称" min-width="150" />
<el-table-column prop="planNo" label="生产计划" min-width="150" />
</el-table>
<!-- 分页 -->
<Pagination
:total="addtotal"
v-model:page="addQueryParams.pageNo"
v-model:limit="addQueryParams.pageSize"
@pagination="handleAddQuery"
/>
<!-- 底部按钮 -->
<template #footer>
<div class="dialog-footer" style="margin-left: 20%;">
<el-button @click="handleAddCancel">取消</el-button>
<el-button type="primary" @click="handleAddConfirm">确认</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup lang="ts">
defineOptions({ name: 'interrupt' })
defineOptions({ name: 'Interrupt' })
import * as PlansubdetailApi from '@/api/heli/plansubdetail'
import {DICT_TYPE, getIntDictOptions} from "@/utils/dict";
import {ref, reactive, onMounted} from "vue"; // onMounted
import * as UserApi from "@/api/system/user";
import {formatDate} from "@/utils/formatTime";
import { DICT_TYPE, getIntDictOptions, getStrDictOptions } from '@/utils/dict'
import { ref, reactive, onMounted } from 'vue' // onMounted
import * as UserApi from '@/api/system/user'
import * as PlanSubApi from '@/api/heli/plansub'
import { formatDate } from '@/utils/formatTime'
import * as shopCalendarApi from '@/api/heli/shopCalendar'
const message = useMessage() //
const { t } = useI18n() //
const reload = inject('reload')
const userInit = ref()
const loading = ref(false)
const loading2 = ref(false)
const loading3 = ref(false)
const list = ref([])
const total = ref(0)
const multipleTableRef = ref()
const addtotal = ref(0)
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
twoDimOwner: undefined,
subType: undefined,
beginTime: undefined,
startTime: undefined,
code: undefined,
name: undefined
})
const queryFormRef = ref()
//
const addDialogVisible = ref(false)
const addList = ref([])
const addQueryParams = reactive({
pageNo: 1,
pageSize: 10,
projectCode: '',
projectSubName: ''
})
const selectedAddRow = ref([])
const rowClickHandle = (row) => {
const selectData = selectedAddRow.value
multipleTableRef.value.clearSelection()
// if( selectData.length == 1 ) {
// selectData.forEach(item => {
// // ,
// if (item == row) {
// multipleTableRef.value.toggleRowSelection(row, false);
// }
// //
// else {
// multipleTableRef.value.toggleRowSelection(row, true);
// }
// })
// }
// else {
// multipleTableRef.value.toggleRowSelection(row, true);
// }
if (selectData && selectData.length == 1) {
const [item] = selectData;
const shouldSelect = item !== row;
multipleTableRef.value.toggleRowSelection(row, shouldSelect);
} else {
multipleTableRef.value.toggleRowSelection(row, true);
}
}
// Checkbox
const handlerSelect = (selection, row) => {
//
multipleTableRef.value.clearSelection()
if(selection.length == 0) return
multipleTableRef.value.toggleRowSelection(row,true)
}
//
const handleSelectionChange = (val) => {
console.log('表格的选中 可以获得当前选中的数据',val);
selectedAddRow.value = val
}
//
const addForm = () => {
resetAddForm()
getAddList()
addDialogVisible.value = true
}
//
const resetAddForm = () => {
addQueryParams.projectCode = ''
addQueryParams.projectSubName = ''
selectedAddRow.value = null
}
//
const getAddList = async () => {
try {
loading3.value = true;
const params = {
projectCode: addQueryParams.projectCode,
projectSubName: addQueryParams.projectSubName
}
const res = await PlansubdetailApi.pageAddList(params)
console.log(res)
addList.value = res.list;
addtotal.value = res.total;
} catch (error) {
message.error('获取项目列表失败:' + error.message)
}finally{
loading3.value = false;
}
}
//
const handleRowSelect = (row) => {
selectedAddRow.value = row
}
//
const handleAddCancel = () => {
ElMessageBox.confirm('是否退出新增?', '提示', {
confirmButtonText: '是',
cancelButtonText: '否',
type: 'warning'
})
.then(() => {
addDialogVisible.value = false
})
.catch(() => {})
}
//
const handleAddConfirm = () => {
for(var i = 0 ; i < list.value.length ; i++ ){
var item = list.value[i];
if(!item.id){
message.warning('列表中存在未保存数据,请确认!');
return
}
}
if (!selectedAddRow.value) {
message.warning('请先选择要添加的项目')
return
}
selectedAddRow.value[0].twoDimDate = null;
selectedAddRow.value[0].startTwoDimDate = null;
selectedAddRow.value[0].twoDimOwner = null;
selectedAddRow.value[0].subType = null;
selectedAddRow.value[0].designNum = null;
selectedAddRow.value[0].seqNo = null;
selectedAddRow.value[0].isAdd = 1;
selectedAddRow.value[0].flag = 1;
selectedAddRow.value[0].userFlag = true;
selectedAddRow.value[0].id = null;
list.value.push(selectedAddRow.value[0])
addDialogVisible.value = false
message.success('项目添加成功')
}
//
const handleAddQuery = () => {
getAddList()
}
//
let isProcessingChange = false
//
const isNewRow = (row) => {
return row.isAdd === 1
}
const saveForm = async () => {
try {
if (list.value) {
loading.value = true
for(var i = 0 ; i < list.value.length ;i++){
var item = list.value[i]
if (item.isOverProcess) {
item.isOverProcess = 1
} else {
item.isOverProcess = 0
}
if(!item.id){
console.log(item)
var type = ("BLUEPRINT_WORKBLANK" == (item.subType))?"毛坯":("BLUEPRINT_2D" == (item.subType))?"2D":("BLUEPRINT_3D" == (item.subType))?'3D':'新增数据';
message.error('该子项目'+item.name+(type == '新增数据'?'新增数据':'设计类型:'+type)+' ,没有保存请确认!')
return
}
}
//
const updateReqVO = {
list: list.value
}
const res = await PlansubdetailApi.operate(updateReqVO)
if (res) {
message.success('保存成功')
}
} else {
message.error('失败:当前页面无数据可供保存')
}
reload() //
} catch (error) {
message.error('失败:' + error.message)
} finally {
loading.value = false
}
}
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
if (queryParams.beginTime) {
queryParams.startTime = queryParams.beginTime + ' 00:00:00'
}
const data = await PlansubdetailApi.getPlanSubDetailPage(queryParams)
list.value = data.list
list.value.forEach(item => {
list.value.forEach((item) => {
item.isAdd = 0
})
total.value = data.total
@ -187,18 +564,175 @@ const getList = async () => {
loading.value = false
}
}
//
const dialogVisible = ref(false)
const dialogTitle = ref('插活前')
const currentRow = ref(null)
const insertList = ref([])
const modification = (row) => {
console.log(row)
const modification = async (row) => {
var data = row as unknown as PlansubdetailApi.PlanSubDetailVO
const res = await PlansubdetailApi.modificationPlanSubDetail(data)
if (res.list) {
//
currentRow.value = row
insertList.value = res.list
dialogVisible.value = true
dialogTitle.value = '插活前'
} else {
message.success('成功')
}
}
//
const addItemRow = (row) => {
if(row.id){
//
const newRow = {
...row,
//
id: null, // id
startTwoDimDate: undefined, //
twoDimDate: undefined, //
designNum: undefined, //
seqNo: undefined, //
isAdd: 1, //
flag: 1, //
userFlag: true
}
//
const currentIndex = list.value.findIndex((item) => item === row)
//
if (currentIndex !== -1) {
list.value.splice(currentIndex + 1, 0, newRow)
} else {
//
list.value.push(newRow)
}
//message.success('')
}else{
message.error('该数据未保存,请确认')
}
}
const getSearchRlTs = async (row, startDateTime: string, endDateTime: string) => {
let data = await PlanSubApi.getSearchRlTsS(
formatDate(startDateTime, 'YYYY-MM-DD'),
formatDate(endDateTime, 'YYYY-MM-DD')
)
row.designNum = data
}
const handleCancelDialog = () => {
ElMessageBox.confirm('是否退出插活?', '提示', {
confirmButtonText: '是',
cancelButtonText: '否',
type: 'warning'
})
.then(() => {
dialogVisible.value = false
})
.catch(() => {
//
})
}
const handleInsert = async () => {
loading2.value = true
//
if (currentRow.value) {
const newRow = { ...currentRow.value }
newRow.id = null // id
insertList.value.push(newRow)
insertList.value.forEach((item) => {
if (item.isOverProcess) {
item.isOverProcess = 1
} else {
item.isOverProcess = 0
}
})
try {
const updateReqVO = {
list: insertList.value
}
//
const res = await PlansubdetailApi.chahuoPlanSubDetail(updateReqVO)
insertList.value = res.list
dialogTitle.value = '插活后'
// if (res) {
// message.success('')
// dialogVisible.value = false
// reload() //
// }
} catch (error) {
message.error('插活失败:' + error.message)
} finally {
loading2.value = false
}
}
}
//
const handleConfirm = async () => {
//
try {
loading2.value = true
const updateReqVO = {
list: insertList.value
}
//
const res = await PlansubdetailApi.savechahuoPlanSubDetail(updateReqVO)
if (res) {
message.success('插活成功')
dialogVisible.value = false
}
} catch (error) {
message.error('插活失败:' + error.message)
} finally {
loading2.value = false
reload() //
}
dialogVisible.value = false
message.success('插活成功')
}
//
const disabledFutureDates = (time) => {
const today = new Date()
today.setHours(0, 0, 0, 0)
return time.getTime() < today.getTime()
}
//
const handleDelete = async (row) => {
if (row.isAdd === 1) {
//
const index = list.value.findIndex((item) => item === row)
if (index !== -1) {
list.value.splice(index, 1)
message.success('删除成功')
}
return
}
//
var today = new Date().toLocaleDateString('en-CA')
var startDate = new Date(row.startTwoDimDate).toLocaleDateString('en-CA')
if (today > startDate) {
message.error('当前日期>开始日期,不允许删除')
return
}
try {
await PlansubdetailApi.deletePlanSubDetail(row.id)
message.success('删除成功')
reload() //
} catch (e) {
console.error('删除失败:', e)
}
}
const change1 = async (row: any, type: number) => {
if (isProcessingChange) return //
isProcessingChange = true
@ -207,11 +741,11 @@ const change1 = async (row: any, type: number) => {
if (row.startTwoDimDate && row.twoDimDate) {
const startTime = new Date(row.startTwoDimDate).getTime()
const endTime = new Date(row.twoDimDate).getTime()
getSearchRlTs(row, row.startTwoDimDate, row.twoDimDate)
if (startTime > endTime) {
// 使 setTimeout message.error
setTimeout(() => {
message.error("开始日期不能大于结束日期,请确认!")
message.error('开始日期不能大于结束日期,请确认!')
}, 100)
if (type === 0) {
@ -230,7 +764,7 @@ const change1 = async (row: any, type: number) => {
if (data <= 0) {
setTimeout(() => {
message.error("选择的日期是节假日,请确认!")
message.error('选择的日期是节假日,请确认!')
}, 100)
if (type === 0) {
@ -249,7 +783,7 @@ const handleQuery = () => {
if (queryParams.twoDimOwner == null) {
// 使 setTimeout message.error
setTimeout(() => {
message.error("负责人为空,请确认")
message.error('负责人为空,请确认')
}, 100)
return // return
}
@ -276,13 +810,48 @@ const resetQuery = () => {
onMounted(async () => {
try {
//
userInit.value = await UserApi.getDeptName("设计部")
userInit.value = await UserApi.getDeptName('设计部')
await getList()
} catch (error) {
console.error('初始化失败:', error)
setTimeout(() => {
message.error("初始化数据失败")
message.error('初始化数据失败')
}, 100)
}
})
</script>
<style scoped>
.dialog-content {
padding: 20px 0;
}
.date-info {
margin-bottom: 20px;
font-size: 16px;
font-weight: bold;
color: #409eff;
}
.status-title {
margin-bottom: 20px;
text-align: center;
}
.status-title h3 {
margin: 0;
color: #303133;
}
.dialog-footer {
text-align: center;
display: flex;
justify-content: center;
align-items: center;
margin-top: 20px;
}
.dialog-footer .el-button {
margin: 0 10px;
min-width: 100px;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@ -18,7 +18,7 @@
<el-button @click="outopen">取消</el-button>
</template>
</Dialog>
<printFinalDialog ref="printref" :minAmount="minAmount" :formData="formData" />
<printFinalDialog ref="printref" :minAmount="minAmount" :formData="formData" />
</template>
<script setup lang="ts">
@ -31,7 +31,7 @@ const startPageNum = ref(0);
const endPageNum = ref(0);
const printref = ref()
const onPrint = () => {
printref.value.open(cnenList.value)
printref.value.open(cnenList.value)
}
@ -49,7 +49,7 @@ const cnenList = ref([])
const bomCodes = ref('')
const open = async (vals) => {
const sortedVals = [...vals].sort((a, b) => {
const sortedVals = [...vals].sort((a, b) => {
return b.id - a.id;
});
@ -78,8 +78,8 @@ const open = async (vals) => {
const formattedDate = `物料编码:${item.code},规格:${item.spec},简称:${item.name},库区:${item.rg},库位:${item.pg}`;
const qrCodeData = await QRCode.toDataURL(formattedDate ,{
errorCorrectionLevel: 'H'
})
errorCorrectionLevel: 'H'
})
const qrCodeElement = document.getElementById('qrCodeContainer')
if (qrCodeElement) {
(qrCodeElement.innerHTML +=
@ -130,12 +130,12 @@ const open = async (vals) => {
</div>
</div>
</div>`)
if(printCodeName.value.length > 1 && i < printCodeName.value.length - 1){
qrCodeElement.innerHTML +=
`<div style="height:3mm; background-color: white; color: white;width:103mm;margin-left:-3mm">
if(printCodeName.value.length > 1 && i < printCodeName.value.length - 1){
qrCodeElement.innerHTML +=
`<div style="height:3mm; background-color: white; color: white;width:103mm;margin-left:-3mm">
</div>`
}
}
}
})
)

View File

@ -127,11 +127,11 @@ const viewClick = async (item) => {
uni.navigateTo({ url })
}
};
const handleScan = () => {
const handleScan = async() => {
uni.scanCode({
success: (res) => {
success: async(res) => {
searchVal.value = res.result
handleSearch({ inputValue: res.result })
await handleSearch({ inputValue: res.result })
},
fail: () => {
uni.showToast({ title: '扫码失败', icon: 'none' })

View File

@ -9,5 +9,5 @@
// export const serviceDomain = 'https://nxhs.cjyx.cc'
// export const serviceDomain = 'https://star.hz-hl.com'
// export const serviceDomain = 'http://222.71.165.187:9010'
// export const serviceDomain = 'http://localhost:8080'
// export const serviceDomain = 'http://localhost:8080'
export const serviceDomain = 'https://nxhs.cjyx.cc'

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -0,0 +1,124 @@
<template>
<view class="picker-view">
<scroll-view
v-for="(num,index) in colNum"
:key="index"
:style="{
width:`${1/colNum*100}%`,
height:'100%',
backgroundColor:index===0?'#F6F6F6':'#FFFFFF'
}"
scroll-y>
<view
:class="['picker-view-item',modelValue[index]==item.value&&'picker-view-item-active']"
v-for="(item,indexs) in colList[index]"
:key="indexs"
@click="onSelect(index,item,indexs)"
>
{{item.label}}
</view>
</scroll-view>
</view>
</template>
<script setup>
import {
ref,
computed
} from "vue";
const props = defineProps({
//
modelValue: {
type: Array,
default: []
},
//
colNum: {
type: Number,
default: 1
},
// options
options: {
type: Array,
default: []
},
// labelvaluechildren
fieldNames: {
type: Object,
default: ()=>{
return {
label: 'label',
value: 'value',
children: 'children',
}
}
},
// truefalse
isFullLinkage: {
type: Boolean,
default: true
},
})
const emits = defineEmits(["update:modelValue","onChange"])
const colList = computed(() => {
const arr = [];
let option = props.options;
for(let i=0;i<props.colNum;i++){
if ((props.modelValue[i] != undefined&&option)||(props.modelValue[i-1]&&option)||(i===0&&option)) {
arr.push(funOptions(option))
const index = option?.findIndex(item=>item[props.fieldNames.value]==props.modelValue[i])
option = (option[index]&&option[index]?.[props.fieldNames.children])||[];
}
}
return arr;
})
const funOptions = (data) => {
return data.map((item) => {
return {
label: item[props.fieldNames.label],
value: item[props.fieldNames.value],
children:item[props.fieldNames.children]||[]
}
})
}
const onSelect = (index,item,indexs) => {
const modelValue = JSON.parse(JSON.stringify(props.modelValue))
if(modelValue[index]!=item.value||!props.isFullLinkage){
modelValue[index] = item.value;
let option = item[props.fieldNames.children]||[]
for(let i=index+1;i<props.colNum;i++){
if(option[0]){
if(props.isFullLinkage){
modelValue[i] = option[0][props.fieldNames.value]
}else{
modelValue.splice(i,modelValue.length)
}
option = option[0]?.[props.fieldNames.children]||[]
}else if(modelValue[i]){
modelValue.splice(i,modelValue.length)
}
}
}
emits("update:modelValue",modelValue)
emits("onChange")
}
</script>
<style lang="scss" scoped>
.picker-view {
width: 100%;
// height: 600rpx;
flex: 1;
overflow: auto;
display: flex;
.picker-view-item{
padding: 30rpx 0;
text-align: center;
font-size:24rpx;
color:#333333;
}
.picker-view-item-active{
color:var(--dropdownThemeColor);
}
}
</style>

View File

@ -0,0 +1,629 @@
<template>
<view :class="['le-dropdown',isCeiling&&'le-dropdown-ceiling']"
:style="`--dropdownThemeColor:${themeColor};--dropdownThemeColorRgb:${hexToRgb(themeColor)}`">
<!-- 导航 -->
<view class="le-dropdown-menu">
<view class="le-dropdown-menu-item" v-for="(item, index) in menuList" :key="index"
@tap.stop="menuClick(index)">
<view class="le-flex">
<text class="le-dropdown-menu-item-text" :style="{
color: index === current ? themeColor : inactiveColor
}">{{item.title}}</text>
<view v-if="item.type==='sort'"
:class="['le-dropdown-menu-item-arrow',item.value==='asc'&&'le-dropdown-menu-item-arrow_top',item.value==='desc'&&'le-dropdown-menu-item-arrow_bottom']">
</view>
<view v-if="item.type!=='sort'"
:class="['le-dropdown-menu-item-basicarrow',index === current&&'le-dropdown-menu-item-basicarrow_rotate']">
</view>
</view>
</view>
</view>
<!-- 展示的内容 -->
<view class="le-dropdown-content" :style="[
{
transition: `opacity ${duration / 1000}s linear`,
top:'auto',
bottom:`calc(100vh - ${contentHeight + windowTop}px)`,
height:`calc(100vh - ${contentHeight + windowTop}px)`
},
contentStyle
]" @tap="close">
<view ref="leDropdownContentPopupRef" class="le-dropdown-content-popup" :style="[popupStyle]"
@tap.stop.prevent>
<block v-for="(item,index) in menuList" :key="index">
<!-- 单选列表 -->
<view class="le-dropdown-popup-content le-dropdown-cell"
v-if="item.type==='cell'&&index === current">
<view :class="['le-dropdown-cell-item',item.value===sItem.value&&'le-dropdown-cell-active']"
v-for="(sItem,sIndex) in item.options" :key="sIndex" @click="onSelectCell(sItem,index)">
<view class="le-dropdown-cell-active-text">{{sItem.label}}</view>
<view v-show="item.value===sItem.value" class="le-dropdown-cell-active-icon"></view>
</view>
</view>
<!-- 级联动选择 -->
<view class="le-dropdown-popup-content le-dropdown-picker"
v-if="item.type==='picker'&&index === current">
<le-dropdown-picker class="le-dropdown-picker-content" v-model="item.value" v-bind="item.componentProps"
@onChange="onPickerChange(item,index)">
</le-dropdown-picker>
<view class="le-dropdown-footer">
<view class="le-dropdown-confirm" @click="onFilterConfirm(item,index)">
{{item.confirmText||'确定'}}
</view>
</view>
</view>
<!-- 筛选 -->
<view class="le-dropdown-popup-content le-dropdown-filter"
v-if="item.type==='filter'&&index === current">
<view class="le-dropdown-filter-scroll">
<view class="le-dropdown-filter-item" v-for="(sItem,sIndex) in item.children" :key="sIndex">
<view class="le-dropdown-filter-title">
{{sItem.title}}
<text class="le-dropdown-filter-subtitle"
v-if="sItem.type==='slider'">{{sItem.value}}{{sItem.suffix}}</text>
</view>
<view class="le-dropdown-filter-content">
<!-- 单选类型 -->
<block v-if="sItem.type==='radio'">
<view v-for="(ssItem,ssIndex) in sItem.options"
:class="['le-dropdown-filter-box',sItem.value===ssItem.value&&'le-dropdown-filter-box-active']"
:key="ssIndex" @click="onRadioFilter(sIndex,ssItem,index)">
{{ssItem.label}}
</view>
</block>
<!-- 多选类型 -->
<block v-else-if="sItem.type==='checkbox'">
<view v-for="(ssItem,ssIndex) in sItem.options"
:class="['le-dropdown-filter-box',sItem.value.includes(ssItem.value)&&'le-dropdown-filter-box-active']"
:key="ssIndex" @click="onCheckboxFilter(sIndex,ssItem,index)">
{{ssItem.label}}
</view>
</block>
<!-- 滑块类型 -->
<block v-else-if="sItem.type==='slider'">
<slider style="width: 100%;" :activeColor="themeColor" :value="sItem.value"
:min="sItem.componentProps.min||0" :max="sItem.componentProps.max||100"
:step="sItem.componentProps.step||1"
:show-value="sItem.componentProps['show-value']||true"
@change="onSliderChange($event,sIndex,ssItem,index)" />
</block>
</view>
</view>
</view>
<view class="le-dropdown-footer">
<view class="le-dropdown-reset" @click="onFilterReset(item,index)">重置</view>
<view class="le-dropdown-confirm" @click="onFilterConfirm(item,index)">
{{item.confirmText||'确定'}}
</view>
</view>
</view>
</block>
</view>
<view class="le-dropdown-content-mask"></view>
</view>
</view>
</template>
<script setup>
/**
* menuList 导航数据
* @property {String} title 导航名称
* @property {String} type =[cell|picker|sort|click|filter] 导航点击展示的类型
* @value cell 下拉选择单选
* @value picker 级联动
* @value sort 排序
* @value click 点击
* @value filter 复杂筛选
* @property {String} value 导航当前选中的值
* @property {Array} options 导航展示可选的数据值
* */
import {
ref,
computed,
getCurrentInstance,
onMounted
} from "vue";
import cloneDeep from './utils/cloneDeep.js';
import hexToRgb from './utils/hexToRgb.js';
import LeDropdownPicker from "./components/le-picker.vue";
const props = defineProps({
//
menuList: {
type: Array,
default: () => {
return [
]
}
},
//
themeColor: {
type: String,
default: "#3185FF"
},
//
inactiveColor: {
type: String,
default: "#333333"
},
//
duration: {
type: [Number, String],
default: 300
},
//
isCeiling: {
type: Boolean,
default: false
},
})
const emits = defineEmits(["open", "close", "update:menuList", "onConfirm", "onChange"])
// 使
const initMenuList = cloneDeep(props.menuList)
const instance = getCurrentInstance(); //
//
const popupStyle = computed(() => {
let style = {};
// Y100%
style.transform = `translateY(${active.value ? 0 : '-100%'})`
style['transition-duration'] = props.duration / 1000 + 's';
return style;
})
//
const current = ref(99999);
//
const contentStyle = ref({
zIndex: -1,
opacity: 0
})
const active = ref(false) //
const contentHeight = ref(0)
const leDropdownContentPopupRef = ref(null)
const windowTop = ref(0)
uni.getSystemInfo({
success(e) {
windowTop.value = e.windowTop;
}
})
//
const menuClick = (index) => {
getContentHeight()
switch (props.menuList[index].type) {
case 'sort':
onSort(index);
break;
case 'click':
onClick(index);
break;
default:
//
if (index === current.value) {
close();
return;
}
open(index);
break;
}
}
//
const open = (index) => {
//
active.value = true;
contentStyle.value.zIndex = 11;
contentStyle.value.opacity = 1;
contentStyle.value.bottom = `0px`;
contentStyle.value.top = `80rpx`;
//
current.value = index;
emits("open", current.value)
}
//
const close = () => {
active.value = false;
contentStyle.value.opacity = 0;
//
setTimeout(() => {
contentStyle.value.zIndex = -1;
current.value = 99999;
contentStyle.value.bottom = `calc(100vh - ${contentHeight.value + windowTop.value}px)`
contentStyle.value.top = 'auto';
}, props.duration)
emits("close", current.value)
}
//
const getContentHeight = () => {
uni.createSelectorQuery()
.in(instance)
.selectAll('.le-dropdown-menu')
.boundingClientRect()
.exec(data => {
contentHeight.value = data[0][0].bottom
});
}
//
const onSort = (index) => {
const type = current.value === 99999 ? current.value : props.menuList[current.value].type
switch (type) {
case 'sort':
case 'click':
case 99999:
start()
break;
default:
close();
setTimeout(() => {
start()
}, props.duration)
break;
}
function start() {
const menuList = cloneDeep(props.menuList);
current.value = index;
menuList[index].value = !menuList[index].value ? 'asc' : menuList[index].value == 'asc' ? 'desc' :
null;
emits("update:menuList", menuList)
emits("onConfirm", menuList[index], index)
}
}
//
const onClick = (index) => {
const type = current.value === 99999 ? current.value : props.menuList[current.value].type
switch (type) {
case 'sort':
case 'click':
case 99999:
start()
break;
default:
close();
setTimeout(() => {
start()
}, props.duration)
break;
}
function start() {
const menuList = cloneDeep(props.menuList);
current.value = index;
emits("onConfirm", menuList[index], index)
}
}
//
const onSelectCell = (sItem, index) => {
const menuList = cloneDeep(props.menuList);
if (menuList[index].autoTitle) {
menuList[index].title = sItem.label;
}
menuList[index].value = sItem.value;
emits("update:menuList", menuList)
close();
emits("onConfirm", menuList[index], index)
}
//
const onRadioFilter = (sIndex, ssItem, index) => {
const menuList = cloneDeep(props.menuList);
menuList[index].children[sIndex].value = ssItem.value;
emits("update:menuList", menuList)
emits("onChange", menuList[index], sIndex, index)
}
//
const onCheckboxFilter = (sIndex, ssItem, index) => {
const menuList = cloneDeep(props.menuList);
const indexs = menuList[index].children[sIndex].value.indexOf(ssItem.value)
if (indexs != -1) {
menuList[index].children[sIndex].value.splice(indexs, 1)
} else {
menuList[index].children[sIndex].value.push(ssItem.value)
}
emits("update:menuList", menuList)
emits("onChange", menuList[index], sIndex, index)
}
//
const onSliderChange = (event, sIndex, ssItem, index) => {
const menuList = cloneDeep(props.menuList);
menuList[index].children[sIndex].value = event.detail.value;
emits("update:menuList", menuList)
emits("onChange", menuList[index], sIndex, index)
}
//
const onSelectFilter = (sIndex, ssItem, index) => {
const menuList = cloneDeep(props.menuList);
menuList[index].active[sIndex] = ssItem.value;
emits("update:menuList", menuList)
emits("onChange", menuList[index], sIndex, index)
}
//
const onFilterReset = (item, index) => {
const menuList = cloneDeep(props.menuList);
menuList[index].children.forEach((items, indexs) => {
items.value = initMenuList[index].children[indexs].value
})
emits("update:menuList", menuList)
// close();
// emits("onConfirm",menuList[index])
}
//
const onFilterConfirm = (item, index) => {
close();
const menuList = cloneDeep(props.menuList);
emits("onConfirm", menuList[index], index)
}
//
const onPickerChange = (item, index) => {
const menuList = cloneDeep(props.menuList);
emits("onChange", menuList[index], null, index)
}
const bindFun = (data) => {
return data
}
onMounted(() => {
getContentHeight()
})
</script>
<style lang="scss" scoped>
.le-flex {
display: flex;
align-items: center;
height: 100%;
}
.le-dropdown {
width: 100%;
position: relative;
.le-dropdown-menu {
display: flex;
position: relative;
z-index: 11;
height: 80rpx;
.le-dropdown-menu-item {
height: 100%;
flex: 1;
display: flex;
justify-content: center;
align-items: center;
.le-dropdown-menu-item-text {
font-size: 24rpx;
}
.le-dropdown-menu-item-arrow {
margin-left: 6rpx;
transition: transform .3s;
align-items: center;
display: flex;
position: relative;
width: 10rpx;
height: 100%;
&::before {
content: '';
position: absolute;
top: calc(50% - 8rpx);
right: -2rpx;
transform: translateY(-50%);
border: 6rpx solid transparent;
border-bottom-color: #C1C1C1;
}
&::after {
content: '';
position: absolute;
top: calc(50% + 8rpx);
right: -2rpx;
transform: translateY(-50%);
border: 6rpx solid transparent;
border-top-color: #C1C1C1;
}
}
.le-dropdown-menu-item-arrow_top {
&::before {
border-bottom-color: var(--dropdownThemeColor);
}
}
.le-dropdown-menu-item-arrow_bottom {
&::after {
border-top-color: var(--dropdownThemeColor);
}
}
.le-dropdown-menu-item-basicarrow {
margin-left: 6rpx;
transition: transform .3s;
align-items: center;
display: flex;
position: relative;
border: 6rpx solid transparent;
border-bottom: 0rpx solid transparent;
border-top-color: #C1C1C1;
}
.le-dropdown-menu-item-basicarrow_rotate {
transform: rotate(180deg);
border-top-color: var(--dropdownThemeColor);
}
}
}
.le-dropdown-content {
position: absolute;
z-index: 8;
width: 100%;
left: 0px;
bottom: 0;
overflow: hidden;
.le-dropdown-content-mask {
position: absolute;
z-index: 9;
background: rgba(0, 0, 0, .3);
width: 100%;
left: 0;
top: 0;
bottom: 0;
}
.le-dropdown-content-popup {
position: relative;
height: 100%;
max-height: 100%;
overflow: auto;
overscroll-behavior: contain;
z-index: 10;
transition: all 0.3s;
transform: translate3D(0, -100%, 0);
}
}
}
.le-dropdown-ceiling {
position: sticky;
top: 0;
z-index: 1;
}
.le-dropdown-popup-content {
font-size: 28rpx;
border-radius: 0 0 20rpx 20rpx;
background-color: #ffffff;
}
//
.le-dropdown-cell {
padding: 0 30rpx;
.le-dropdown-cell-item {
padding: 20rpx 0;
color: #333333;
font-size: 28rpx;
border-bottom: 1rpx solid #D5D5D5;
display: flex;
align-items: center;
justify-content: space-between;
.le-dropdown-cell-active-text {
flex: 1;
padding-right: 20rpx;
}
}
.le-dropdown-cell-item:last-child {
border-bottom: 0rpx solid #D5D5D5;
}
.le-dropdown-cell-active {
color: var(--dropdownThemeColor);
.le-dropdown-cell-active-icon {
width: 12rpx;
height: 28rpx;
margin-right: 10rpx;
border-color: var(--dropdownThemeColor);
border-style: solid;
border-width: 0 4rpx 4rpx 0;
transform: rotate(45deg);
}
}
}
//
.le-dropdown-filter {
height: 100%;
display: flex;
flex-direction: column;
.le-dropdown-filter-item {
padding: 0 26rpx;
}
.le-dropdown-filter-title {
padding-top: 34rpx;
margin-bottom: 18rpx;
color: #333333;
font-size: 24rpx;
.le-dropdown-filter-subtitle {
margin-left: 10rpx;
color: var(--dropdownThemeColor);
}
}
.le-dropdown-filter-content {
display: flex;
flex-wrap: wrap;
}
.le-dropdown-filter-box {
width: 200rpx;
margin-right: 30rpx;
margin-bottom: 14rpx;
padding: 18rpx 0;
display: flex;
align-items: center;
justify-content: center;
font-size: 28rpx;
color: #333333;
background-color: #F5F5F5;
border-radius: 999rpx;
}
.le-dropdown-filter-box-active {
color: var(--dropdownThemeColor);
background-color: rgba(var(--dropdownThemeColorRgb), 0.04);
}
}
.le-dropdown-filter-scroll{
flex: 1;
overflow: auto;
}
//
.le-dropdown-picker{
height: 100%;
display: flex;
flex-direction: column;
}
.le-dropdown-footer {
display: flex;
align-items: center;
margin-top: 14rpx;
.le-dropdown-reset {
flex: 1;
margin: 26rpx;
display: flex;
align-items: center;
justify-content: center;
height: 68rpx;
font-size: 28rpx;
background-color: #FFFFFF;
color: var(--dropdownThemeColor);
border: 2rpx solid var(--dropdownThemeColor);
border-radius: 999rpx;
}
.le-dropdown-confirm {
flex: 1;
margin: 26rpx;
display: flex;
align-items: center;
justify-content: center;
height: 68rpx;
font-size: 28rpx;
background-color: var(--dropdownThemeColor);
border: 2rpx solid var(--dropdownThemeColor);
color: #ffffff;
border-radius: 999rpx;
}
}
</style>

View File

@ -0,0 +1,23 @@
export default function(hexStr){
//十六进制颜色值的正则表达式
let reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
let sColor = hexStr.toLowerCase();
if (sColor && reg.test(sColor)) {
if (sColor.length === 4) {
let sColorNew = "#";
for (let i = 1; i < 4; i += 1) {
sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1));
}
sColor = sColorNew;
}
//处理六位的颜色值f
let sColorChange = [];
for (let i = 1; i < 7; i += 2) {
sColorChange.push(parseInt(`0x${sColor.slice(i, i + 2)}`));
}
let rgbText = sColorChange.join(",")
return rgbText;
} else {
return sColor;
}
}

View File

@ -86,6 +86,7 @@ export const http = <T>(options: UniApp.RequestOptions) => {
...options,
// 响应成功
success(res) {
console.log(res)
// 状态码 2xx axios 就是这样设计的
if (res.statusCode >= 200 && res.statusCode < 300) {
if (res.data?.code == 0) {