diff --git a/klp-crm/src/main/java/com/klp/crm/domain/bo/CrmOrderBo.java b/klp-crm/src/main/java/com/klp/crm/domain/bo/CrmOrderBo.java index 8f8bc7597..7ec2aa370 100644 --- a/klp-crm/src/main/java/com/klp/crm/domain/bo/CrmOrderBo.java +++ b/klp-crm/src/main/java/com/klp/crm/domain/bo/CrmOrderBo.java @@ -265,4 +265,14 @@ public class CrmOrderBo extends BaseEntity { @JsonFormat(pattern = "yyyy-MM-dd") private Date deliveryDateEnd; + @DateTimeFormat(pattern = "yyyy-MM-dd") + @JsonFormat(pattern = "yyyy-MM-dd") + private Date bindDateStart; + + @DateTimeFormat(pattern = "yyyy-MM-dd") + @JsonFormat(pattern = "yyyy-MM-dd") + private Date bindDateEnd; + + private Boolean onlyBoundSchedule; + } diff --git a/klp-crm/src/main/java/com/klp/crm/service/impl/CrmOrderServiceImpl.java b/klp-crm/src/main/java/com/klp/crm/service/impl/CrmOrderServiceImpl.java index e6baee4c8..4a0807530 100644 --- a/klp-crm/src/main/java/com/klp/crm/service/impl/CrmOrderServiceImpl.java +++ b/klp-crm/src/main/java/com/klp/crm/service/impl/CrmOrderServiceImpl.java @@ -247,6 +247,24 @@ public class CrmOrderServiceImpl implements ICrmOrderService { qw.lt(bo.getSignDateEnd() != null, "co.sign_time", addOneDay(bo.getSignDateEnd())); qw.ge(bo.getDeliveryDateStart() != null, "co.delivery_date", bo.getDeliveryDateStart()); qw.lt(bo.getDeliveryDateEnd() != null, "co.delivery_date", addOneDay(bo.getDeliveryDateEnd())); + boolean applyBoundFilter = Boolean.TRUE.equals(bo.getOnlyBoundSchedule()) + || bo.getBindDateStart() != null + || bo.getBindDateEnd() != null; + if (applyBoundFilter) { + StringBuilder existsSql = new StringBuilder(); + List args = new ArrayList<>(); + existsSql.append("exists (select 1 from sch_sale_schedule_rel rel where rel.del_flag = 0 and rel.order_id = co.order_id"); + if (bo.getBindDateStart() != null) { + existsSql.append(" and rel.create_time >= {").append(args.size()).append("}"); + args.add(bo.getBindDateStart()); + } + if (bo.getBindDateEnd() != null) { + existsSql.append(" and rel.create_time < {").append(args.size()).append("}"); + args.add(addOneDay(bo.getBindDateEnd())); + } + existsSql.append(")"); + qw.apply(existsSql.toString(), args.toArray()); + } if(bo.getOrderIds() !=null){ qw.in(!bo.getOrderIds().isEmpty(), "co.order_id", bo.getOrderIds()); } diff --git a/klp-flow/src/main/java/com/klp/flow/controller/SchProdScheduleItemController.java b/klp-flow/src/main/java/com/klp/flow/controller/SchProdScheduleItemController.java index 6112cfe64..9b87bdf57 100644 --- a/klp-flow/src/main/java/com/klp/flow/controller/SchProdScheduleItemController.java +++ b/klp-flow/src/main/java/com/klp/flow/controller/SchProdScheduleItemController.java @@ -23,6 +23,7 @@ import com.klp.flow.domain.bo.SchProdScheduleItemBo; import com.klp.flow.domain.bo.SchProdScheduleItemMergeBo; import com.klp.flow.domain.bo.SchProdScheduleItemReceiveBo; import com.klp.flow.domain.bo.SchProdScheduleItemMergeValidateBo; +import com.klp.flow.domain.bo.SchProdScheduleItemSortBo; import com.klp.flow.service.ISchProdScheduleItemService; import com.klp.common.core.page.TableDataInfo; @@ -138,4 +139,9 @@ public class SchProdScheduleItemController extends BaseController { public R mergeValidate(@Validated @RequestBody SchProdScheduleItemMergeValidateBo validateBo) { return R.ok(iSchProdScheduleItemService.validateMerge(validateBo)); } + + @PostMapping("/sort") + public R saveSort(@Validated @RequestBody SchProdScheduleItemSortBo sortBo) { + return toAjax(iSchProdScheduleItemService.saveSort(sortBo)); + } } diff --git a/klp-flow/src/main/java/com/klp/flow/domain/SchProdScheduleItem.java b/klp-flow/src/main/java/com/klp/flow/domain/SchProdScheduleItem.java index 478c6cc0a..e21abec87 100644 --- a/klp-flow/src/main/java/com/klp/flow/domain/SchProdScheduleItem.java +++ b/klp-flow/src/main/java/com/klp/flow/domain/SchProdScheduleItem.java @@ -135,6 +135,10 @@ public class SchProdScheduleItem extends BaseEntity { * 工序ID */ private Long actionId; + /** + * 排序号 + */ + private Integer sortNo; /** * 规格 例:1.0X1250 */ diff --git a/klp-flow/src/main/java/com/klp/flow/domain/bo/SchProdScheduleItemBo.java b/klp-flow/src/main/java/com/klp/flow/domain/bo/SchProdScheduleItemBo.java index d8ef353f6..24ae30f5e 100644 --- a/klp-flow/src/main/java/com/klp/flow/domain/bo/SchProdScheduleItemBo.java +++ b/klp-flow/src/main/java/com/klp/flow/domain/bo/SchProdScheduleItemBo.java @@ -162,6 +162,10 @@ public class SchProdScheduleItemBo extends BaseEntity { * 工序ID */ private Long actionId; + /** + * 排序号 + */ + private Integer sortNo; /** * 规格 例:1.0X1250 diff --git a/klp-flow/src/main/java/com/klp/flow/domain/bo/SchProdScheduleItemSortBo.java b/klp-flow/src/main/java/com/klp/flow/domain/bo/SchProdScheduleItemSortBo.java new file mode 100644 index 000000000..e705b6de1 --- /dev/null +++ b/klp-flow/src/main/java/com/klp/flow/domain/bo/SchProdScheduleItemSortBo.java @@ -0,0 +1,14 @@ +package com.klp.flow.domain.bo; + +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import java.util.List; + +@Data +public class SchProdScheduleItemSortBo { + + @NotEmpty(message = "scheduleIds不能为空") + private List scheduleIds; +} + diff --git a/klp-flow/src/main/java/com/klp/flow/domain/vo/SchProdScheduleItemVo.java b/klp-flow/src/main/java/com/klp/flow/domain/vo/SchProdScheduleItemVo.java index 13dd55394..e1162b47e 100644 --- a/klp-flow/src/main/java/com/klp/flow/domain/vo/SchProdScheduleItemVo.java +++ b/klp-flow/src/main/java/com/klp/flow/domain/vo/SchProdScheduleItemVo.java @@ -202,6 +202,11 @@ public class SchProdScheduleItemVo { @TableField(exist = false) private String stepName; + /** + * 排序号 + */ + private Integer sortNo; + /** * 规格 例:1.0X1250 */ diff --git a/klp-flow/src/main/java/com/klp/flow/service/ISchProdScheduleItemService.java b/klp-flow/src/main/java/com/klp/flow/service/ISchProdScheduleItemService.java index 1eea0f013..4a47d5c03 100644 --- a/klp-flow/src/main/java/com/klp/flow/service/ISchProdScheduleItemService.java +++ b/klp-flow/src/main/java/com/klp/flow/service/ISchProdScheduleItemService.java @@ -7,6 +7,7 @@ import com.klp.flow.domain.bo.SchProdScheduleItemBo; import com.klp.flow.domain.bo.SchProdScheduleItemMergeBo; import com.klp.flow.domain.bo.SchProdScheduleItemReceiveBo; import com.klp.flow.domain.bo.SchProdScheduleItemMergeValidateBo; +import com.klp.flow.domain.bo.SchProdScheduleItemSortBo; import com.klp.common.core.page.TableDataInfo; import com.klp.common.core.domain.PageQuery; @@ -70,4 +71,9 @@ public interface ISchProdScheduleItemService { * 合并校验:检查待合并记录来源产需单的 header 字段是否一致 */ SchProdScheduleItemMergeValidateVo validateMerge(SchProdScheduleItemMergeValidateBo validateBo); + + /** + * 保存已排产拖拽排序 + */ + Boolean saveSort(SchProdScheduleItemSortBo sortBo); } diff --git a/klp-flow/src/main/java/com/klp/flow/service/impl/SchProdScheduleItemServiceImpl.java b/klp-flow/src/main/java/com/klp/flow/service/impl/SchProdScheduleItemServiceImpl.java index e6c3bd07b..80076d069 100644 --- a/klp-flow/src/main/java/com/klp/flow/service/impl/SchProdScheduleItemServiceImpl.java +++ b/klp-flow/src/main/java/com/klp/flow/service/impl/SchProdScheduleItemServiceImpl.java @@ -13,6 +13,7 @@ import com.klp.flow.domain.bo.SchProdScheduleItemBo; import com.klp.flow.domain.bo.SchProdScheduleItemMergeBo; import com.klp.flow.domain.bo.SchProdScheduleItemReceiveBo; import com.klp.flow.domain.bo.SchProdScheduleItemMergeValidateBo; +import com.klp.flow.domain.bo.SchProdScheduleItemSortBo; import com.klp.flow.domain.vo.SchProdScheduleItemVo; import com.klp.flow.domain.vo.SchProdScheduleItemMergeValidateVo; import com.klp.flow.domain.SchProdScheduleItem; @@ -56,7 +57,12 @@ public class SchProdScheduleItemServiceImpl implements ISchProdScheduleItemServi */ @Override public SchProdScheduleItemVo queryById(Long scheduleId){ - return baseMapper.selectVoById(scheduleId); + SchProdScheduleItemVo vo = baseMapper.selectVoById(scheduleId); + if (vo != null) { + fillStepName(java.util.Collections.singletonList(vo)); + fillMissingHeaderFields(java.util.Collections.singletonList(vo)); + } + return vo; } /** @@ -68,6 +74,7 @@ public class SchProdScheduleItemServiceImpl implements ISchProdScheduleItemServi Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); if (result.getRecords() != null && !result.getRecords().isEmpty()) { fillStepName(result.getRecords()); + fillMissingHeaderFields(result.getRecords()); } return TableDataInfo.build(result); } @@ -81,6 +88,7 @@ public class SchProdScheduleItemServiceImpl implements ISchProdScheduleItemServi List list = baseMapper.selectVoList(lqw); if (list != null && !list.isEmpty()) { fillStepName(list); + fillMissingHeaderFields(list); } return list; } @@ -121,6 +129,8 @@ public class SchProdScheduleItemServiceImpl implements ISchProdScheduleItemServi lqw.eq(StringUtils.isNotBlank(bo.getRowRemark()), SchProdScheduleItem::getRowRemark, bo.getRowRemark()); // actionId lqw.eq(bo.getActionId() != null, SchProdScheduleItem::getActionId, bo.getActionId()); + lqw.orderByAsc(SchProdScheduleItem::getSortNo); + lqw.orderByAsc(SchProdScheduleItem::getScheduleId); return lqw; } @@ -148,6 +158,149 @@ public class SchProdScheduleItemServiceImpl implements ISchProdScheduleItemServi } } + private void fillMissingHeaderFields(List voList) { + List missingList = voList.stream() + .filter(vo -> StringUtils.isBlank(vo.getCustomerName()) + || StringUtils.isBlank(vo.getBusinessUser()) + || StringUtils.isBlank(vo.getBusinessPhone()) + || vo.getDeliveryCycle() == null + || StringUtils.isBlank(vo.getProductType()) + || StringUtils.isBlank(vo.getUsePurpose())) + .collect(Collectors.toList()); + + if (missingList.isEmpty()) { + return; + } + + List scheduleNos = missingList.stream() + .map(SchProdScheduleItemVo::getScheduleNo) + .filter(StringUtils::isNotBlank) + .distinct() + .collect(Collectors.toList()); + + if (scheduleNos.isEmpty()) { + return; + } + + List headers = schProdScheduleMapper.selectList( + Wrappers.lambdaQuery() + .in(SchProdSchedule::getScheduleNo, scheduleNos) + ); + Map headerMap = headers.stream() + .collect(Collectors.toMap(SchProdSchedule::getScheduleNo, h -> h, (v1, v2) -> v1)); + + for (SchProdScheduleItemVo vo : missingList) { + SchProdSchedule header = headerMap.get(vo.getScheduleNo()); + if (header == null) { + continue; + } + + boolean changed = false; + SchProdScheduleItem update = new SchProdScheduleItem(); + update.setScheduleId(vo.getScheduleId()); + + if (StringUtils.isBlank(vo.getCustomerName()) && StringUtils.isNotBlank(header.getCustomerName())) { + vo.setCustomerName(header.getCustomerName()); + update.setCustomerName(header.getCustomerName()); + changed = true; + } + if (StringUtils.isBlank(vo.getBusinessUser()) && StringUtils.isNotBlank(header.getBusinessUser())) { + vo.setBusinessUser(header.getBusinessUser()); + update.setBusinessUser(header.getBusinessUser()); + changed = true; + } + if (StringUtils.isBlank(vo.getBusinessPhone()) && StringUtils.isNotBlank(header.getBusinessPhone())) { + vo.setBusinessPhone(header.getBusinessPhone()); + update.setBusinessPhone(header.getBusinessPhone()); + changed = true; + } + if (vo.getDeliveryCycle() == null && header.getDeliveryCycle() != null) { + vo.setDeliveryCycle(header.getDeliveryCycle()); + update.setDeliveryCycle(header.getDeliveryCycle()); + changed = true; + } + if (StringUtils.isBlank(vo.getProductType()) && StringUtils.isNotBlank(header.getProductType())) { + vo.setProductType(header.getProductType()); + update.setProductType(header.getProductType()); + changed = true; + } + if (StringUtils.isBlank(vo.getUsePurpose()) && StringUtils.isNotBlank(header.getUsePurpose())) { + vo.setUsePurpose(header.getUsePurpose()); + update.setUsePurpose(header.getUsePurpose()); + changed = true; + } + if (StringUtils.isBlank(vo.getThicknessTolerance()) && StringUtils.isNotBlank(header.getThicknessTolerance())) { + vo.setThicknessTolerance(header.getThicknessTolerance()); + update.setThicknessTolerance(header.getThicknessTolerance()); + changed = true; + } + if (StringUtils.isBlank(vo.getWidthTolerance()) && StringUtils.isNotBlank(header.getWidthTolerance())) { + vo.setWidthTolerance(header.getWidthTolerance()); + update.setWidthTolerance(header.getWidthTolerance()); + changed = true; + } + if (StringUtils.isBlank(vo.getSurfaceQuality()) && StringUtils.isNotBlank(header.getSurfaceQuality())) { + vo.setSurfaceQuality(header.getSurfaceQuality()); + update.setSurfaceQuality(header.getSurfaceQuality()); + changed = true; + } + if (StringUtils.isBlank(vo.getSurfaceTreatment()) && StringUtils.isNotBlank(header.getSurfaceTreatment())) { + vo.setSurfaceTreatment(header.getSurfaceTreatment()); + update.setSurfaceTreatment(header.getSurfaceTreatment()); + changed = true; + } + if (StringUtils.isBlank(vo.getInnerDiameter()) && StringUtils.isNotBlank(header.getInnerDiameter())) { + vo.setInnerDiameter(header.getInnerDiameter()); + update.setInnerDiameter(header.getInnerDiameter()); + changed = true; + } + if (StringUtils.isBlank(vo.getOuterDiameter()) && StringUtils.isNotBlank(header.getOuterDiameter())) { + vo.setOuterDiameter(header.getOuterDiameter()); + update.setOuterDiameter(header.getOuterDiameter()); + changed = true; + } + if (StringUtils.isBlank(vo.getPackReq()) && StringUtils.isNotBlank(header.getPackReq())) { + vo.setPackReq(header.getPackReq()); + update.setPackReq(header.getPackReq()); + changed = true; + } + if (StringUtils.isBlank(vo.getCutEdgeReq()) && StringUtils.isNotBlank(header.getCutEdgeReq())) { + vo.setCutEdgeReq(header.getCutEdgeReq()); + update.setCutEdgeReq(header.getCutEdgeReq()); + changed = true; + } + if (StringUtils.isBlank(vo.getSingleCoilWeight()) && StringUtils.isNotBlank(header.getSingleCoilWeight())) { + vo.setSingleCoilWeight(header.getSingleCoilWeight()); + update.setSingleCoilWeight(header.getSingleCoilWeight()); + changed = true; + } + if (StringUtils.isBlank(vo.getWeightDeviation()) && StringUtils.isNotBlank(header.getWeightDeviation())) { + vo.setWeightDeviation(header.getWeightDeviation()); + update.setWeightDeviation(header.getWeightDeviation()); + changed = true; + } + if (StringUtils.isBlank(vo.getOtherTechReq()) && StringUtils.isNotBlank(header.getOtherTechReq())) { + vo.setOtherTechReq(header.getOtherTechReq()); + update.setOtherTechReq(header.getOtherTechReq()); + changed = true; + } + if (StringUtils.isBlank(vo.getPaymentDesc()) && StringUtils.isNotBlank(header.getPaymentDesc())) { + vo.setPaymentDesc(header.getPaymentDesc()); + update.setPaymentDesc(header.getPaymentDesc()); + changed = true; + } + if (StringUtils.isBlank(vo.getRemark()) && StringUtils.isNotBlank(header.getRemark())) { + vo.setRemark(header.getRemark()); + update.setRemark(header.getRemark()); + changed = true; + } + + if (changed) { + baseMapper.updateById(update); + } + } + } + /** * 新增排产单主加明细可合并 */ @@ -504,6 +657,22 @@ public class SchProdScheduleItemServiceImpl implements ISchProdScheduleItemServi return vo; } + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean saveSort(SchProdScheduleItemSortBo sortBo) { + List scheduleIds = sortBo.getScheduleIds(); + for (int i = 0; i < scheduleIds.size(); i++) { + Long id = scheduleIds.get(i); + baseMapper.update( + null, + Wrappers.lambdaUpdate() + .set(SchProdScheduleItem::getSortNo, i + 1) + .eq(SchProdScheduleItem::getScheduleId, id) + ); + } + return true; + } + /** * 反射获取字段值(用于动态字段比较 — SchProdSchedule header) */ diff --git a/klp-flow/src/main/resources/mapper/flow/SchProdScheduleItemMapper.xml b/klp-flow/src/main/resources/mapper/flow/SchProdScheduleItemMapper.xml index b63fb9c33..6131a8fb4 100644 --- a/klp-flow/src/main/resources/mapper/flow/SchProdScheduleItemMapper.xml +++ b/klp-flow/src/main/resources/mapper/flow/SchProdScheduleItemMapper.xml @@ -33,6 +33,7 @@ + diff --git a/klp-ui/src/api/aps/schedule.js b/klp-ui/src/api/aps/schedule.js index 71056bdf5..7b375a690 100644 --- a/klp-ui/src/api/aps/schedule.js +++ b/klp-ui/src/api/aps/schedule.js @@ -99,3 +99,11 @@ export function mergeScheduleItem(data) { data }) } + +export function saveScheduleItemSort(data) { + return request({ + url: '/flow/prodScheduleItem/sort', + method: 'post', + data + }) +} diff --git a/klp-ui/src/views/wms/post/aps/orderTrack.vue b/klp-ui/src/views/wms/post/aps/orderTrack.vue index 3942bc3f5..e9ff89e02 100644 --- a/klp-ui/src/views/wms/post/aps/orderTrack.vue +++ b/klp-ui/src/views/wms/post/aps/orderTrack.vue @@ -32,6 +32,22 @@ +
+ 绑定日期: + +
@@ -209,6 +225,29 @@ export default { batchTargetContractId: '', batchTransferCoilIds: [], batchTransferLoading: false, + bindDateRange: [], + bindDatePickerOptions: { + shortcuts: [ + { + text: '今天', + onClick(picker) { + const today = new Date() + const start = new Date(today.getFullYear(), today.getMonth(), today.getDate()) + const end = new Date(today.getFullYear(), today.getMonth(), today.getDate()) + picker.$emit('pick', [start, end]) + } + }, + { + text: '最近7天', + onClick(picker) { + const end = new Date() + const start = new Date() + start.setDate(start.getDate() - 6) + picker.$emit('pick', [start, end]) + } + } + ] + }, queryParams: { keyword: '', orderCode: '', @@ -218,6 +257,9 @@ export default { signDateEnd: undefined, deliveryDateStart: undefined, deliveryDateEnd: undefined, + bindDateStart: undefined, + bindDateEnd: undefined, + onlyBoundSchedule: true, pageNum: 1, pageSize: 10 } @@ -249,9 +291,35 @@ export default { } }, created() { + this.initBindDateRange() this.getList() }, methods: { + formatDate(date) { + if (!date) return '' + const y = date.getFullYear() + const m = String(date.getMonth() + 1).padStart(2, '0') + const d = String(date.getDate()).padStart(2, '0') + return `${y}-${m}-${d}` + }, + initBindDateRange() { + const end = new Date() + const start = new Date() + start.setDate(start.getDate() - 6) + this.bindDateRange = [this.formatDate(start), this.formatDate(end)] + }, + syncBindQueryParams() { + const range = this.bindDateRange || [] + if (Array.isArray(range) && range.length === 2 && range[0] && range[1]) { + this.queryParams.bindDateStart = range[0] + this.queryParams.bindDateEnd = range[1] + this.queryParams.onlyBoundSchedule = true + return + } + this.queryParams.bindDateStart = undefined + this.queryParams.bindDateEnd = undefined + this.queryParams.onlyBoundSchedule = false + }, toggleMoreFilter() { this.showMoreFilter = !this.showMoreFilter }, @@ -267,9 +335,11 @@ export default { this.queryParams.signDateEnd = undefined this.queryParams.deliveryDateStart = undefined this.queryParams.deliveryDateEnd = undefined + this.initBindDateRange() this.handleSearch() }, getList() { + this.syncBindQueryParams() this.orderLoading = true listCrmOrder(this.queryParams).then(res => { this.orderList = res.rows || [] diff --git a/klp-ui/src/views/wms/post/aps/schedule.vue b/klp-ui/src/views/wms/post/aps/schedule.vue index cdc8fb3f8..4047323f8 100644 --- a/klp-ui/src/views/wms/post/aps/schedule.vue +++ b/klp-ui/src/views/wms/post/aps/schedule.vue @@ -44,21 +44,29 @@
- 接收 - 驳回 + 接收 + 驳回
+ + + + + + + + + + - - - - - - + + - - - - - + - - @@ -99,8 +99,6 @@ - - @@ -111,22 +109,24 @@ - - - - - - - - + + - + + + + + + + + + - +
排产单号 {{ sch.scheduleNo }} 生产日期 {{ sch.prodDate }}
排产状态 {{ statusMap[sch.scheduleStatus] || '未知' }} @@ -67,28 +75,20 @@ {{ sch.businessUser }}
联系电话{{ sch.businessPhone }} 订货单位 {{ sch.customerName }}
联系电话{{ sch.businessPhone }} 交货期(天) {{ sch.deliveryCycle }}产品用途{{ sch.usePurpose }}
品名{{ sch.productType }}{{ sch.productType }}
厚度公差 {{ sch.thicknessTolerance }} 宽度公差 {{ sch.widthTolerance }}
表面质量 {{ sch.surfaceQuality }} 表面处理{{ sch.innerDiameter }} 外径要求 {{ sch.outerDiameter }}
包装要求 {{ sch.packReq }} 切边要求{{ sch.singleCoilWeight }} 交货重量偏差 {{ sch.weightDeviation }}
其他技术要求{{ sch.otherTechReq }}
付款情况说明{{ sch.paymentDesc }}产品用途{{ sch.usePurpose || '-' }}
备注{{ sch.remark }}{{ sch.remark || '-' }}
其他技术要求{{ sch.otherTechReq }}
付款情况说明{{ sch.paymentDesc }}
驳回原因{{ sch.returnReason }}{{ sch.returnReason }}
@@ -156,7 +156,7 @@
暂无明细
-
+
{{ hasQueried ? '该日期暂无待审核产需单' : '请选择日期查询' }}
@@ -184,53 +184,78 @@ + + + + + + + + + + - - + + + + + + + + - - + + + + + + + + - - + + + + + + + + - + + + + + + + + - + + + + + + - - - - - - - - - - - - - - - - - - + + - + + - - - - + +
排产单号{{ sch.scheduleNo }}生产日期{{ sch.prodDate }}排产单号{{ sch.scheduleNo }}生产日期{{ sch.prodDate }}排产状态 + 已接收 + 业务员{{ sch.businessUser }}
业务员{{ sch.businessUser }}联系电话{{ sch.businessPhone }}订货单位{{ sch.customerName }}联系电话{{ sch.businessPhone }}交货期(天){{ sch.deliveryCycle }}品名{{ sch.productType }}
订货单位{{ sch.customerName }}交货期(天){{ sch.deliveryCycle }}厚度公差{{ sch.thicknessTolerance }}宽度公差{{ sch.widthTolerance }}表面质量{{ sch.surfaceQuality }}表面处理{{ sch.surfaceTreatment }}
品名{{ sch.productType }}内径尺寸{{ sch.innerDiameter }}外径要求{{ sch.outerDiameter }}包装要求{{ sch.packReq }}切边要求{{ sch.cutEdgeReq }}
产品用途{{ sch.usePurpose }}单件重量{{ sch.singleCoilWeight }}交货重量偏差{{ sch.weightDeviation }}产品用途{{ sch.usePurpose || '-' }}
厚度公差{{ sch.thicknessTolerance }}宽度公差{{ sch.widthTolerance }}
表面质量{{ sch.surfaceQuality }}表面处理{{ sch.surfaceTreatment }}
内径尺寸{{ sch.innerDiameter }}外径要求{{ sch.outerDiameter }}
包装要求{{ sch.packReq }}切边要求{{ sch.cutEdgeReq }}
单件重量{{ sch.singleCoilWeight }}交货重量偏差{{ sch.weightDeviation }}备注{{ sch.remark || '-' }}
其他技术要求{{ sch.otherTechReq }}其他技术要求{{ sch.otherTechReq }}
付款情况说明{{ sch.paymentDesc }}
备注{{ sch.remark }}付款情况说明{{ sch.paymentDesc }}
@@ -254,7 +279,7 @@
暂无明细
-
+
{{ hasQueried ? '该日期暂无已接收产需单' : '请选择日期查询' }}
@@ -284,64 +309,66 @@ {{ tab }} {{ scheduledItemList.filter(i => normalizeStepName(i.stepName) === tab).length }} +
+ 保存排序 +
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
+
+
生产日期{{ row.prodDate }}
+
规格{{ row.spec }}
+
材质{{ row.material }}
+
排产吨数{{ row.scheduleWeight }}
+
品名项{{ row.productItem }}
+
品名{{ row.productType }}
+
订货单位{{ row.customerName }}
+
业务员{{ row.businessUser }}
+
联系电话{{ row.businessPhone }}
+
交货期(天){{ row.deliveryCycle }}
+
厚度公差{{ row.thicknessTolerance }}
+
宽度公差{{ row.widthTolerance }}
+
表面质量{{ row.surfaceQuality }}
+
表面处理{{ row.surfaceTreatment }}
+
内径尺寸{{ row.innerDiameter }}
+
外径要求{{ row.outerDiameter }}
+
包装要求{{ row.packReq }}
+
切边要求{{ row.cutEdgeReq }}
+
单件重量{{ row.singleCoilWeight }}
+
交货重量偏差{{ row.weightDeviation }}
+
产品用途{{ row.usePurpose }}
+
其他技术要求{{ row.otherTechReq }}
+
付款情况说明{{ row.paymentDesc }}
+
单行排产备注{{ row.rowRemark }}
+
备注{{ row.remark }}
+
+
+ + +
{{ hasQueried ? '该日期暂无已排产数据' : '请选择日期查询' }} @@ -645,14 +672,16 @@ import { listScheduleItem, updateScheduleItem, delScheduleItem, - receiveScheduleItem + receiveScheduleItem, + saveScheduleItemSort } from '@/api/aps/schedule' import { PROCESSES } from '@/utils/meta' import ProcessSelect from '@/components/KLPService/ProcessSelect/index.vue' +import draggable from 'vuedraggable' export default { name: 'ApsSchedule', - components: { ProcessSelect }, + components: { ProcessSelect, draggable }, data() { const today = new Date() const y = today.getFullYear() @@ -678,6 +707,10 @@ export default { // 已排产 scheduledItemList: [], scheduledStepTab: '', + scheduledOrderMap: {}, + scheduledStepItems: [], + scheduledSortDirtyMap: {}, + saveSortLoading: false, // 驳回 rejectDialogVisible: false, @@ -724,13 +757,82 @@ export default { return this.scheduledItemList.filter( item => this.normalizeStepName(item.stepName) === tab ) + }, + scheduledSortDirty() { + const tab = this.scheduledStepTab + if (!tab) return false + return !!this.scheduledSortDirtyMap[tab] + } + }, + watch: { + scheduledStepTab() { + this.refreshScheduledStepItems() } }, - watch: {}, created() { this.handleQuery() }, methods: { + getScheduledItemKey(row) { + return row && row.scheduleId != null ? String(row.scheduleId) : '' + }, + refreshScheduledStepItems() { + const tab = this.scheduledStepTab + if (!tab) { + this.scheduledStepItems = [] + return + } + const stepItems = this.scheduledItemList.filter(i => this.normalizeStepName(i.stepName) === tab) + const order = this.scheduledOrderMap[tab] + if (!Array.isArray(order) || order.length === 0) { + const keys = stepItems.map(i => this.getScheduledItemKey(i)).filter(Boolean) + this.$set(this.scheduledOrderMap, tab, keys) + this.scheduledStepItems = stepItems.slice() + return + } + const indexMap = new Map(order.map((k, idx) => [k, idx])) + this.scheduledStepItems = stepItems + .slice() + .sort((a, b) => { + const ka = this.getScheduledItemKey(a) + const kb = this.getScheduledItemKey(b) + const ia = indexMap.has(ka) ? indexMap.get(ka) : 999999 + const ib = indexMap.has(kb) ? indexMap.get(kb) : 999999 + return ia - ib + }) + const existKeys = new Set(stepItems.map(i => this.getScheduledItemKey(i))) + const nextOrder = order.filter(k => existKeys.has(k)) + const missing = stepItems.map(i => this.getScheduledItemKey(i)).filter(k => k && !nextOrder.includes(k)) + if (missing.length) { + nextOrder.push(...missing) + } + if (nextOrder.join('|') !== order.join('|')) { + this.$set(this.scheduledOrderMap, tab, nextOrder) + } + }, + handleScheduledDragEnd() { + const tab = this.scheduledStepTab + if (!tab) return + const keys = (this.scheduledStepItems || []).map(i => this.getScheduledItemKey(i)).filter(Boolean) + this.$set(this.scheduledOrderMap, tab, keys) + this.$set(this.scheduledSortDirtyMap, tab, true) + }, + handleSaveScheduledSort() { + const tab = this.scheduledStepTab + if (!tab) return + const scheduleIds = (this.scheduledStepItems || []).map(i => i.scheduleId).filter(v => v != null) + if (scheduleIds.length === 0) return + this.saveSortLoading = true + saveScheduleItemSort({ scheduleIds }).then(() => { + this.$modal.msgSuccess('排序已保存') + this.$set(this.scheduledSortDirtyMap, tab, false) + this.queryScheduled() + }).catch(() => { + this.$modal.msgError('保存排序失败') + }).finally(() => { + this.saveSortLoading = false + }) + }, getEmptyEditForm() { return { scheduleId: undefined, @@ -929,14 +1031,18 @@ export default { this.schLoading = true this.scheduledItemList = [] this.scheduledStepTab = '' + this.scheduledOrderMap = {} + this.scheduledStepItems = [] + this.scheduledSortDirtyMap = {} listScheduleItem({ prodDate: this.queryDate, pageNum: 1, pageSize: 999 }).then(res => { - this.scheduledItemList = (res.rows || []).sort((a, b) => (a.scheduleNo || '').localeCompare(b.scheduleNo || '')) + this.scheduledItemList = res.rows || [] // 默认选中第一个步骤tab const tabs = this.scheduledStepTabs if (tabs.length > 0) { this.scheduledStepTab = tabs[0] } + this.refreshScheduledStepItems() const totalWeight = this.scheduledItemList.reduce((sum, d) => { const w = parseFloat(d.scheduleWeight) return sum + (isNaN(w) ? 0 : w) @@ -945,6 +1051,9 @@ export default { }).catch((e) => { console.error('queryScheduled error:', e) this.scheduledItemList = [] + this.scheduledOrderMap = {} + this.scheduledStepItems = [] + this.scheduledSortDirtyMap = {} this.summaryText = '' }).finally(() => { this.schLoading = false @@ -1046,20 +1155,20 @@ export default { .aps-sch-page { height: 100%; - padding: 8px; + padding: 6px; box-sizing: border-box; background: $aps-bg; display: flex; flex-direction: column; - gap: 12px; + gap: 10px; } // 工具栏 .aps-sch-toolbar { display: flex; align-items: center; - gap: 10px; - padding: 10px 16px; + gap: 8px; + padding: 8px 12px; background: $aps-white; border: 1px solid $aps-border; border-radius: $aps-radius; @@ -1126,6 +1235,15 @@ export default { @include aps-btn-red; } +.aps-btn-red.is-disabled, +.aps-btn-red.is-disabled:hover, +.aps-btn-red.is-disabled:focus, +.aps-btn-red.is-disabled:active { + color: $aps-silver-4; + background: $aps-silver-2; + border-color: $aps-silver-3; +} + .detail-card { background: $aps-white; border: 1px solid $aps-border; @@ -1137,7 +1255,7 @@ export default { .detail-card-header { background: linear-gradient(to right, $aps-red-2, $aps-red-3); color: white; - padding: 8px 14px; + padding: 6px 12px; font-size: 13px; font-weight: 600; display: flex; @@ -1147,7 +1265,7 @@ export default { } .detail-card-body { - padding: 14px; + padding: 10px; } .form-grid-2 { @@ -1197,8 +1315,8 @@ export default { .aps-sch-list { display: flex; flex-direction: column; - gap: 10px; - padding: 8px; + gap: 8px; + padding: 6px; } .aps-sch-item { @@ -1213,7 +1331,7 @@ export default { display: flex; align-items: center; justify-content: space-between; - padding: 8px 14px; + padding: 6px 12px; background: linear-gradient(135deg, $aps-silver-1 0%, #f8f9fb 100%); border-bottom: 1px solid $aps-border; } @@ -1221,7 +1339,7 @@ export default { .aps-sch-item-header-left { display: flex; align-items: center; - gap: 12px; + gap: 10px; flex: 1; min-width: 0; } @@ -1238,7 +1356,7 @@ export default { .aps-status-tag { display: inline-block; font-size: 11px; - padding: 2px 8px; + padding: 2px 6px; border-radius: 3px; font-weight: 500; white-space: nowrap; @@ -1254,15 +1372,17 @@ export default { width: 100%; border-collapse: collapse; font-size: 12px; + table-layout: fixed; td { - padding: 5px 10px; + padding: 3px 6px; border: 1px solid $aps-silver-mid; vertical-align: middle; + word-break: break-word; } .req-td-label { - width: 100px; + width: 80px; background: $aps-silver-1; color: $aps-text-muted; font-weight: 500; @@ -1272,6 +1392,15 @@ export default { .req-td-value { color: $aps-text; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .req-td-value[colspan] { + overflow: visible; + text-overflow: clip; + white-space: normal; } } @@ -1283,9 +1412,9 @@ export default { .aps-sch-item-actions { display: flex; - gap: 6px; + gap: 4px; flex-shrink: 0; - margin-left: 12px; + margin-left: 8px; } // 明细表 @@ -1298,7 +1427,7 @@ export default { padding: 7px 14px; background: $aps-silver-1; border-bottom: 1px solid $aps-border; - font-size: 12px; + font-size: 14px; font-weight: 600; color: $aps-text; } @@ -1307,7 +1436,7 @@ export default { display: flex; padding: 7px 14px; border-bottom: 1px solid $aps-silver-mid; - font-size: 12px; + font-size: 14px; color: $aps-text; cursor: pointer; transition: background 0.15s; @@ -1330,7 +1459,7 @@ export default { } .aps-sch-item-empty { - padding: 20px; + padding: 14px; text-align: center; color: $aps-text-muted; font-size: 12px; @@ -1370,6 +1499,12 @@ export default { border-bottom: 1px solid $aps-border; } +.aps-step-tabs-right { + margin-left: auto; + display: flex; + align-items: center; +} + .aps-step-tab { display: inline-flex; align-items: center; @@ -1417,4 +1552,135 @@ export default { background: rgba(255, 255, 255, 0.25); } } + +.aps-scheduled-cards { + padding: 10px 10px 12px; +} + +.aps-scheduled-card { + background: $aps-white; + border: 1px solid $aps-border; + border-radius: $aps-radius; + box-shadow: $aps-shadow-sm; + overflow: hidden; +} + +.aps-scheduled-card + .aps-scheduled-card { + margin-top: 10px; +} + +.aps-scheduled-card-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + padding: 8px 12px; + background: linear-gradient(135deg, $aps-silver-1 0%, #f8f9fb 100%); + border-bottom: 1px solid $aps-border; +} + +.aps-scheduled-card-title { + display: flex; + align-items: center; + gap: 10px; + min-width: 0; + flex: 1; +} + +.aps-drag-handle { + cursor: grab; + color: $aps-text-muted; + font-size: 16px; + flex: 0 0 auto; +} + +.aps-scheduled-no { + color: $aps-red-2; + font-weight: 600; + font-size: 13px; + white-space: nowrap; +} + +.aps-scheduled-step { + color: $aps-text-muted; + font-size: 12px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.aps-scheduled-card-actions { + display: flex; + align-items: center; + gap: 4px; + flex: 0 0 auto; +} + +.aps-scheduled-card-body { + padding: 10px 12px 12px; +} + +.aps-scheduled-kv { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 8px 12px; +} + +.kv-item { + min-width: 0; + display: flex; + align-items: baseline; + gap: 8px; +} + +.kv-label { + flex: 0 0 auto; + color: $aps-text-muted; + font-size: 12px; + white-space: nowrap; +} + +.kv-value { + color: $aps-text; + font-size: 12px; + font-weight: 500; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.kv-value-wrap { + white-space: normal; + overflow: visible; + text-overflow: clip; +} + +.kv-span-2 { + grid-column: span 2; +} + +.kv-span-4 { + grid-column: 1 / -1; +} + +.aps-drag-ghost { + opacity: 0.6; +} + +@media (max-width: 1366px) { + .aps-scheduled-kv { + grid-template-columns: repeat(3, minmax(0, 1fr)); + } +} + +@media (max-width: 1024px) { + .aps-scheduled-kv { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .kv-span-2 { + grid-column: span 2; + } +} diff --git a/script/sql/mysql/update/update_20260709_sch_prod_schedule_item_sort_no.sql b/script/sql/mysql/update/update_20260709_sch_prod_schedule_item_sort_no.sql new file mode 100644 index 000000000..c7d24aa0d --- /dev/null +++ b/script/sql/mysql/update/update_20260709_sch_prod_schedule_item_sort_no.sql @@ -0,0 +1,3 @@ +ALTER TABLE sch_prod_schedule_item + ADD COLUMN sort_no INT NOT NULL DEFAULT 999999 AFTER action_id; +