fix: 完善日计划开始确认与取消入口
This commit is contained in:
@@ -426,7 +426,7 @@ git commit -m "feat: 增加LMS日计划管理接口"
|
||||
|
||||
- [ ] **步骤 4:实现开始订单和详情**
|
||||
|
||||
开始订单弹窗展示当前数量并允许填写追加数量。详情抽屉展示三类状态时间和按时间倒序的操作记录。
|
||||
开始订单弹窗展示原计划量、确认计划量、已有追加、本次追加和开始后总量;确认计划量为必填正整数,ERP 与人工来源都可在开始时确认。服务端在同一事务内原子更新计划量、累计追加量和订单状态,并分别记录数量调整、追加和开始日志。管理页为未开始订单提供填写原因的取消入口。详情抽屉展示三类状态时间和按时间倒序的操作记录。
|
||||
|
||||
- [ ] **步骤 5:运行局部 ESLint**
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
- 人工新增日计划。
|
||||
- 编辑未开始的人工日计划。
|
||||
- 对未开始订单执行“开始订单”。
|
||||
- 对未开始订单执行“取消订单”,填写原因后可从作业页恢复。
|
||||
- 已结束订单只在本页面查询,不进入作业页面。
|
||||
|
||||
查询条件在桌面端一行多项展示,包括日计划编号或 ERP 订单号、计划日期范围、管芯编码或名称、来源和订单状态。
|
||||
@@ -136,7 +137,7 @@ ERP 推送不允许直接修改顺序、权重、当前完成数量或作业状
|
||||
|
||||
人工创建字段包括计划日期、人工订单号、管芯物料、计划数量、装箱信息、顺序和权重。人工订单号允许手填;未填写时使用 LMS 日计划编号作为订单号。
|
||||
|
||||
只有未开始的人工来源日计划允许编辑基本信息。ERP 来源计划通过 ERP 幂等推送维护,管理页面只读。开始订单时允许再次确认计划数量,并可填写追加数量;开始成功后进入日计划作业页面。
|
||||
只有未开始的人工来源日计划允许编辑基本信息。ERP 来源计划通过 ERP 幂等推送维护,管理页面只读。开始订单时 ERP 和人工来源均允许再次确认计划数量,并可填写追加数量;计划数量、累计追加数量和开始状态在同一事务中原子更新,开始成功后进入日计划作业页面。
|
||||
|
||||
追加数量仅允许订单进行中时执行,必须大于零,按累计值保存并记录每次追加明细。
|
||||
|
||||
|
||||
@@ -9,6 +9,10 @@ import lombok.EqualsAndHashCode;
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class DailyPlanStartReqVO extends DailyPlanVersionReqVO {
|
||||
@NotNull(message = "确认计划数量不能为空")
|
||||
@Min(value = 1, message = "确认计划数量必须为正整数")
|
||||
private Integer planQty;
|
||||
|
||||
@NotNull(message = "追加数量不能为空")
|
||||
@Min(value = 0, message = "追加数量不能小于0")
|
||||
private Integer appendQty;
|
||||
|
||||
@@ -94,6 +94,9 @@ public interface DailyPlanMapper extends BaseMapperX<DailyPlanDO> {
|
||||
*/
|
||||
int updateStateWithVersion(@Param("plan") DailyPlanDO plan);
|
||||
|
||||
/** 原子确认数量并开始未开始订单。 */
|
||||
int startOrderWithVersion(@Param("plan") DailyPlanDO plan);
|
||||
|
||||
/**
|
||||
* 乐观锁恢复已取消的订单状态,并清空前一订单状态。
|
||||
*/
|
||||
|
||||
@@ -359,19 +359,32 @@ public class DailyPlanServiceImpl implements DailyPlanService {
|
||||
checkAffected(dailyPlanMapper.updateNotStartedPlan(update));
|
||||
}
|
||||
|
||||
/** 开始订单并写入追加数量。 */
|
||||
/** 开始订单,同时确认计划数量并写入本次追加数量。 */
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void startOrder(DailyPlanStartReqVO reqVO) {
|
||||
DailyPlanDO current = validateVersion(reqVO.getId(), reqVO.getVersion());
|
||||
validateOrderStatus(current, DailyPlanOrderStatusEnum.NOT_STARTED, "开始订单");
|
||||
DailyPlanDO update = newUpdate(current);
|
||||
int confirmedPlanQty = reqVO.getPlanQty();
|
||||
int appendQty = safeAddQuantity(current.getAppendQty(), reqVO.getAppendQty());
|
||||
safeAddQuantity(confirmedPlanQty, appendQty); // 校验开始后的需求总量不会溢出。
|
||||
update.setPlanQty(confirmedPlanQty);
|
||||
update.setOrderStatus(DailyPlanOrderStatusEnum.IN_PROGRESS.getCode());
|
||||
update.setOrderStartTime(LocalDateTime.now());
|
||||
update.setAppendQty(safeAddQuantity(current.getAppendQty(), reqVO.getAppendQty()));
|
||||
checkAffected(dailyPlanMapper.updateStateWithVersion(update));
|
||||
update.setAppendQty(appendQty);
|
||||
checkAffected(dailyPlanMapper.startOrderWithVersion(update));
|
||||
if (!current.getPlanQty().equals(confirmedPlanQty)) {
|
||||
insertLog(current.getDailyPlanId(), TARGET_QUANTITY, TYPE_UPDATE,
|
||||
String.valueOf(current.getPlanQty()), String.valueOf(confirmedPlanQty),
|
||||
confirmedPlanQty - current.getPlanQty(), null);
|
||||
}
|
||||
if (reqVO.getAppendQty() > 0) {
|
||||
insertLog(current.getDailyPlanId(), TARGET_QUANTITY, TYPE_APPEND,
|
||||
String.valueOf(current.getAppendQty()), String.valueOf(appendQty), reqVO.getAppendQty(), null);
|
||||
}
|
||||
insertLog(current.getDailyPlanId(), TARGET_ORDER, TYPE_START, String.valueOf(current.getOrderStatus()),
|
||||
String.valueOf(update.getOrderStatus()), reqVO.getAppendQty(), null);
|
||||
String.valueOf(update.getOrderStatus()), null, null);
|
||||
}
|
||||
|
||||
/** 追加进行中订单的数量。 */
|
||||
|
||||
@@ -246,6 +246,20 @@
|
||||
AND deleted = b'0'
|
||||
</update>
|
||||
|
||||
<update id="startOrderWithVersion">
|
||||
UPDATE lms_daily_plan
|
||||
SET plan_qty = #{plan.planQty},
|
||||
append_qty = #{plan.appendQty},
|
||||
order_status = 1,
|
||||
order_start_time = #{plan.orderStartTime},
|
||||
updater = #{plan.updater},
|
||||
version = version + 1
|
||||
WHERE daily_plan_id = #{plan.dailyPlanId}
|
||||
AND version = #{plan.version}
|
||||
AND order_status = 0
|
||||
AND deleted = b'0'
|
||||
</update>
|
||||
|
||||
<update id="updateSortWithVersion">
|
||||
UPDATE lms_daily_plan
|
||||
SET sort_seq = #{sortSeq}, updater = #{updater}, version = version + 1
|
||||
|
||||
@@ -84,6 +84,7 @@ export namespace LmsDailyPlanApi {
|
||||
|
||||
export interface StartReq extends VersionReq {
|
||||
appendQty: number;
|
||||
planQty: number;
|
||||
}
|
||||
|
||||
export interface AppendReq extends VersionReq {
|
||||
|
||||
@@ -7,6 +7,7 @@ import { Page, useVbenDrawer, useVbenModal } from '@vben/common-ui';
|
||||
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
import { getDailyPlanManagementPage } from '#/api/lms/dailyplan';
|
||||
|
||||
import Operation from '../work/modules/operation.vue';
|
||||
import { useGridColumns, useGridFormSchema } from './data';
|
||||
import Detail from './modules/detail.vue';
|
||||
import Form from './modules/form.vue';
|
||||
@@ -27,6 +28,10 @@ const [StartOrderModal, startOrderModalApi] = useVbenModal({
|
||||
connectedComponent: StartOrder,
|
||||
destroyOnClose: true,
|
||||
});
|
||||
const [OperationModal, operationModalApi] = useVbenModal({
|
||||
connectedComponent: Operation,
|
||||
destroyOnClose: true,
|
||||
});
|
||||
|
||||
function handleRefresh() {
|
||||
gridApi.query();
|
||||
@@ -48,6 +53,10 @@ function handleStart(row: LmsDailyPlanApi.DailyPlan) {
|
||||
startOrderModalApi.setData(row).open();
|
||||
}
|
||||
|
||||
function handleCancel(row: LmsDailyPlanApi.DailyPlan) {
|
||||
operationModalApi.setData({ row, type: 'cancelOrder' }).open();
|
||||
}
|
||||
|
||||
const [Grid, gridApi] = useVbenVxeGrid({
|
||||
formOptions: {
|
||||
schema: useGridFormSchema(),
|
||||
@@ -82,6 +91,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||
<FormDrawer @success="handleRefresh" />
|
||||
<DetailDrawer />
|
||||
<StartOrderModal @success="handleRefresh" />
|
||||
<OperationModal @success="handleRefresh" />
|
||||
<Grid table-title="日计划管理">
|
||||
<template #toolbar-tools>
|
||||
<TableAction
|
||||
@@ -126,6 +136,14 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||
ifShow: row.orderStatus === ORDER_NOT_STARTED,
|
||||
onClick: handleStart.bind(null, row),
|
||||
},
|
||||
{
|
||||
label: '取消订单',
|
||||
type: 'link',
|
||||
danger: true,
|
||||
auth: ['lms:daily-plan:operate'],
|
||||
ifShow: row.orderStatus === ORDER_NOT_STARTED,
|
||||
onClick: handleCancel.bind(null, row),
|
||||
},
|
||||
]"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -11,12 +11,17 @@ import { startDailyPlanOrder } from '#/api/lms/dailyplan';
|
||||
|
||||
const emit = defineEmits(['success']);
|
||||
const row = ref<LmsDailyPlanApi.DailyPlan>();
|
||||
const planQty = ref(1);
|
||||
const appendQty = ref(0);
|
||||
const totalAfterStart = computed(() => (row.value?.totalQty ?? 0) + appendQty.value);
|
||||
const totalAfterStart = computed(() => planQty.value + (row.value?.appendQty ?? 0) + appendQty.value);
|
||||
|
||||
const [Modal, modalApi] = useVbenModal({
|
||||
async onConfirm() {
|
||||
if (!row.value) return;
|
||||
if (!Number.isInteger(planQty.value) || planQty.value <= 0) {
|
||||
message.warning('确认计划数量必须为正整数');
|
||||
return;
|
||||
}
|
||||
if (!Number.isInteger(appendQty.value) || appendQty.value < 0) {
|
||||
message.warning('追加数量必须为不小于 0 的整数');
|
||||
return;
|
||||
@@ -26,6 +31,7 @@ const [Modal, modalApi] = useVbenModal({
|
||||
await startDailyPlanOrder({
|
||||
id: row.value.dailyPlanId,
|
||||
version: row.value.version,
|
||||
planQty: planQty.value,
|
||||
appendQty: appendQty.value,
|
||||
});
|
||||
await modalApi.close();
|
||||
@@ -38,10 +44,12 @@ const [Modal, modalApi] = useVbenModal({
|
||||
onOpenChange(isOpen: boolean) {
|
||||
if (!isOpen) {
|
||||
row.value = undefined;
|
||||
planQty.value = 1;
|
||||
appendQty.value = 0;
|
||||
return;
|
||||
}
|
||||
row.value = modalApi.getData<LmsDailyPlanApi.DailyPlan>();
|
||||
planQty.value = row.value.planQty;
|
||||
appendQty.value = 0;
|
||||
},
|
||||
});
|
||||
@@ -52,7 +60,10 @@ const [Modal, modalApi] = useVbenModal({
|
||||
<Descriptions v-if="row" bordered :column="1" size="small">
|
||||
<DescriptionsItem label="日计划编号">{{ row.planCode }}</DescriptionsItem>
|
||||
<DescriptionsItem label="管芯">{{ row.materialCode }} / {{ row.materialName }}</DescriptionsItem>
|
||||
<DescriptionsItem label="当前计划数量">{{ row.planQty }}</DescriptionsItem>
|
||||
<DescriptionsItem label="原计划数量">{{ row.planQty }}</DescriptionsItem>
|
||||
<DescriptionsItem label="确认计划数量">
|
||||
<InputNumber v-model:value="planQty" :min="1" :precision="0" class="w-full" />
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem label="已有追加数量">{{ row.appendQty }}</DescriptionsItem>
|
||||
<DescriptionsItem label="本次追加数量">
|
||||
<InputNumber v-model:value="appendQty" :min="0" :precision="0" class="w-full" />
|
||||
|
||||
@@ -56,6 +56,7 @@ CROSS JOIN (
|
||||
UNION ALL SELECT 4, '日计划启动', 'lms:daily-plan:start'
|
||||
UNION ALL SELECT 5, '日计划排程', 'lms:daily-plan:schedule'
|
||||
UNION ALL SELECT 6, '日计划策略', 'lms:daily-plan:strategy'
|
||||
UNION ALL SELECT 7, '日计划操作', 'lms:daily-plan:operate'
|
||||
) permission
|
||||
WHERE menu.id = COALESCE(
|
||||
(SELECT fixed.id FROM system_menu fixed WHERE fixed.id=2093000000000000100 AND fixed.deleted=b'0'),
|
||||
@@ -63,7 +64,10 @@ WHERE menu.id = COALESCE(
|
||||
WHERE fallback.component='lms/daily-plan/management/index' AND fallback.deleted=b'0')
|
||||
)
|
||||
AND menu.deleted=b'0'
|
||||
AND NOT EXISTS (SELECT 1 FROM system_menu existing WHERE existing.permission=permission.code AND existing.deleted=b'0');
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM system_menu existing
|
||||
WHERE existing.parent_id=menu.id AND existing.permission=permission.code AND existing.deleted=b'0'
|
||||
);
|
||||
|
||||
-- 作业页面独立挂载自身实际使用的按钮权限,避免仅授权作业菜单时按钮全部不可见。
|
||||
INSERT INTO system_menu
|
||||
|
||||
Reference in New Issue
Block a user