fix: 优化日计划日志展示
This commit is contained in:
@@ -16,5 +16,6 @@ public class DailyPlanOperationLogRespVO {
|
|||||||
private Integer changeQty;
|
private Integer changeQty;
|
||||||
private String operationReason;
|
private String operationReason;
|
||||||
private String operator;
|
private String operator;
|
||||||
|
private String operatorName;
|
||||||
private LocalDateTime operationTime;
|
private LocalDateTime operationTime;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ import cn.code.nl.module.lms.enums.DailyPlanSourceTypeEnum;
|
|||||||
import cn.code.nl.module.lms.enums.DailyPlanStrategyModeEnum;
|
import cn.code.nl.module.lms.enums.DailyPlanStrategyModeEnum;
|
||||||
import cn.code.nl.module.lms.enums.DailyPlanStrategyTypeEnum;
|
import cn.code.nl.module.lms.enums.DailyPlanStrategyTypeEnum;
|
||||||
import cn.code.nl.module.lms.enums.DailyPlanWorkStatusEnum;
|
import cn.code.nl.module.lms.enums.DailyPlanWorkStatusEnum;
|
||||||
|
import cn.code.nl.module.system.api.user.AdminUserApi;
|
||||||
|
import cn.code.nl.module.system.api.user.dto.AdminUserRespDTO;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
@@ -46,7 +48,10 @@ import java.time.LocalDateTime;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static cn.code.nl.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.code.nl.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
import static cn.code.nl.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
import static cn.code.nl.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||||
@@ -90,6 +95,8 @@ public class DailyPlanServiceImpl implements DailyPlanService {
|
|||||||
@Resource
|
@Resource
|
||||||
private CodeGenApi codeGenApi;
|
private CodeGenApi codeGenApi;
|
||||||
@Resource
|
@Resource
|
||||||
|
private AdminUserApi adminUserApi;
|
||||||
|
@Resource
|
||||||
private PlatformTransactionManager transactionManager;
|
private PlatformTransactionManager transactionManager;
|
||||||
|
|
||||||
/** ERP 幂等推送日计划,并在首次推送并发冲突时进行一次独立事务重试。 */
|
/** ERP 幂等推送日计划,并在首次推送并发冲突时进行一次独立事务重试。 */
|
||||||
@@ -234,8 +241,16 @@ public class DailyPlanServiceImpl implements DailyPlanService {
|
|||||||
if (dailyPlanMapper.selectDailyPlanById(dailyPlanId) == null) {
|
if (dailyPlanMapper.selectDailyPlanById(dailyPlanId) == null) {
|
||||||
throw exception(DAILY_PLAN_NOT_EXISTS);
|
throw exception(DAILY_PLAN_NOT_EXISTS);
|
||||||
}
|
}
|
||||||
List<DailyPlanOperationLogRespVO> result = new ArrayList<>();
|
List<DailyPlanOperationLogDO> logs = dailyPlanOperationLogMapper.selectListByDailyPlanId(dailyPlanId);
|
||||||
for (DailyPlanOperationLogDO log : dailyPlanOperationLogMapper.selectListByDailyPlanId(dailyPlanId)) {
|
Set<Long> operatorIds = logs.stream()
|
||||||
|
.map(DailyPlanOperationLogDO::getOperator)
|
||||||
|
.map(DailyPlanServiceImpl::parseOperatorId)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
Map<Long, AdminUserRespDTO> userMap = operatorIds.isEmpty()
|
||||||
|
? Map.of() : adminUserApi.getUserMap(operatorIds);
|
||||||
|
List<DailyPlanOperationLogRespVO> result = new ArrayList<>(logs.size());
|
||||||
|
for (DailyPlanOperationLogDO log : logs) {
|
||||||
DailyPlanOperationLogRespVO response = new DailyPlanOperationLogRespVO();
|
DailyPlanOperationLogRespVO response = new DailyPlanOperationLogRespVO();
|
||||||
response.setOperationLogId(log.getOperationLogId());
|
response.setOperationLogId(log.getOperationLogId());
|
||||||
response.setDailyPlanId(log.getDailyPlanId());
|
response.setDailyPlanId(log.getDailyPlanId());
|
||||||
@@ -246,12 +261,37 @@ public class DailyPlanServiceImpl implements DailyPlanService {
|
|||||||
response.setChangeQty(log.getChangeQty());
|
response.setChangeQty(log.getChangeQty());
|
||||||
response.setOperationReason(log.getOperationReason());
|
response.setOperationReason(log.getOperationReason());
|
||||||
response.setOperator(log.getOperator());
|
response.setOperator(log.getOperator());
|
||||||
|
response.setOperatorName(resolveOperatorName(log.getOperator(), userMap));
|
||||||
response.setOperationTime(log.getOperationTime());
|
response.setOperationTime(log.getOperationTime());
|
||||||
result.add(response);
|
result.add(response);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 批量翻译操作人;ERP 和系统操作不交给用户翻译,避免把非数字标识当用户 ID。 */
|
||||||
|
private static String resolveOperatorName(String operator, Map<Long, AdminUserRespDTO> userMap) {
|
||||||
|
if (ERP_OPERATOR.equalsIgnoreCase(operator)) {
|
||||||
|
return "ERP";
|
||||||
|
}
|
||||||
|
Long operatorId = parseOperatorId(operator);
|
||||||
|
if (operatorId == null) {
|
||||||
|
return "系统";
|
||||||
|
}
|
||||||
|
AdminUserRespDTO user = userMap.get(operatorId);
|
||||||
|
return user == null ? "未知用户" : user.getNickname();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Long parseOperatorId(String operator) {
|
||||||
|
if (StrUtil.isBlank(operator) || !operator.chars().allMatch(Character::isDigit)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return Long.valueOf(operator);
|
||||||
|
} catch (NumberFormatException ignored) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** 查询全部日计划策略。 */
|
/** 查询全部日计划策略。 */
|
||||||
@Override
|
@Override
|
||||||
public List<DailyPlanStrategyRespVO> getStrategies() {
|
public List<DailyPlanStrategyRespVO> getStrategies() {
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ export namespace LmsDailyPlanApi {
|
|||||||
operationTime: number;
|
operationTime: number;
|
||||||
operationType: string;
|
operationType: string;
|
||||||
operator: string;
|
operator: string;
|
||||||
|
operatorName?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Strategy {
|
export interface Strategy {
|
||||||
|
|||||||
@@ -124,10 +124,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
|||||||
type: 'link',
|
type: 'link',
|
||||||
auth: ['lms:daily-plan:start'],
|
auth: ['lms:daily-plan:start'],
|
||||||
ifShow: row.orderStatus === ORDER_NOT_STARTED,
|
ifShow: row.orderStatus === ORDER_NOT_STARTED,
|
||||||
popConfirm: {
|
onClick: handleStart.bind(null, row),
|
||||||
title: `确认开始日计划「${row.planCode}」吗?`,
|
|
||||||
confirm: handleStart.bind(null, row),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
]"
|
]"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { ref } from 'vue';
|
|||||||
|
|
||||||
import { useVbenDrawer } from '@vben/common-ui';
|
import { useVbenDrawer } from '@vben/common-ui';
|
||||||
import { DICT_TYPE } from '@vben/constants';
|
import { DICT_TYPE } from '@vben/constants';
|
||||||
|
import { getDictLabel } from '@vben/hooks';
|
||||||
import { formatDateTime } from '@vben/utils';
|
import { formatDateTime } from '@vben/utils';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -21,11 +22,51 @@ const DAILY_PLAN_DICT_TYPE = DICT_TYPE as typeof DICT_TYPE & {
|
|||||||
LMS_DAILY_PLAN_SOURCE_TYPE: string;
|
LMS_DAILY_PLAN_SOURCE_TYPE: string;
|
||||||
LMS_DAILY_PLAN_WORK_STATUS: string;
|
LMS_DAILY_PLAN_WORK_STATUS: string;
|
||||||
};
|
};
|
||||||
|
const TARGET_LABELS: Record<string, string> = {
|
||||||
|
ORDER: '订单',
|
||||||
|
QUANTITY: '数量',
|
||||||
|
SLEEVING: '套管',
|
||||||
|
SORT: '顺序',
|
||||||
|
STOCKING: '备货',
|
||||||
|
STRATEGY: '策略',
|
||||||
|
WEIGHT: '权重',
|
||||||
|
};
|
||||||
|
const TYPE_LABELS: Record<string, string> = {
|
||||||
|
APPEND: '追加数量',
|
||||||
|
CANCEL: '取消',
|
||||||
|
CREATE: '创建',
|
||||||
|
FINISH: '结束',
|
||||||
|
PROGRESS: '更新进度',
|
||||||
|
RESTORE: '恢复',
|
||||||
|
START: '开始',
|
||||||
|
STOP: '停止',
|
||||||
|
UPDATE: '修改',
|
||||||
|
};
|
||||||
|
const STATUS_OPERATION_TYPES = new Set(['CANCEL', 'FINISH', 'RESTORE', 'START', 'STOP']);
|
||||||
|
|
||||||
function showTime(value?: number) {
|
function showTime(value?: number) {
|
||||||
return value ? formatDateTime(value) : '-';
|
return value ? formatDateTime(value) : '-';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showTarget(value: string) {
|
||||||
|
return TARGET_LABELS[value] ?? '其他';
|
||||||
|
}
|
||||||
|
|
||||||
|
function showType(value: string) {
|
||||||
|
return TYPE_LABELS[value] ?? '操作';
|
||||||
|
}
|
||||||
|
|
||||||
|
function showLogValue(log: LmsDailyPlanApi.OperationLog, value?: string) {
|
||||||
|
if (!value) return '-';
|
||||||
|
if (!STATUS_OPERATION_TYPES.has(log.operationType)) return value;
|
||||||
|
const dictType = log.operationTarget === 'ORDER'
|
||||||
|
? DAILY_PLAN_DICT_TYPE.LMS_DAILY_PLAN_ORDER_STATUS
|
||||||
|
: ['SLEEVING', 'STOCKING'].includes(log.operationTarget)
|
||||||
|
? DAILY_PLAN_DICT_TYPE.LMS_DAILY_PLAN_WORK_STATUS
|
||||||
|
: undefined;
|
||||||
|
return dictType ? (getDictLabel(dictType, value) || '未知状态') : value;
|
||||||
|
}
|
||||||
|
|
||||||
const [Drawer, drawerApi] = useVbenDrawer({
|
const [Drawer, drawerApi] = useVbenDrawer({
|
||||||
showConfirmButton: false,
|
showConfirmButton: false,
|
||||||
async onOpenChange(isOpen: boolean) {
|
async onOpenChange(isOpen: boolean) {
|
||||||
@@ -84,12 +125,12 @@ const [Drawer, drawerApi] = useVbenDrawer({
|
|||||||
<Empty v-if="logs.length === 0" description="暂无操作记录" />
|
<Empty v-if="logs.length === 0" description="暂无操作记录" />
|
||||||
<Timeline v-else>
|
<Timeline v-else>
|
||||||
<TimelineItem v-for="log in logs" :key="String(log.operationLogId)">
|
<TimelineItem v-for="log in logs" :key="String(log.operationLogId)">
|
||||||
<div class="font-medium">{{ log.operationType }} · {{ log.operationTarget }}</div>
|
<div class="font-medium">{{ showType(log.operationType) }} · {{ showTarget(log.operationTarget) }}</div>
|
||||||
<div class="text-sm text-gray-500">{{ showTime(log.operationTime) }} · {{ log.operator || '-' }}</div>
|
<div class="text-sm text-gray-500">{{ showTime(log.operationTime) }} · {{ log.operatorName || '系统' }}</div>
|
||||||
<div v-if="log.beforeValue || log.afterValue" class="mt-1">
|
<div v-if="log.beforeValue || log.afterValue" class="mt-1">
|
||||||
{{ log.beforeValue || '-' }} → {{ log.afterValue || '-' }}
|
变更:{{ showLogValue(log, log.beforeValue) }} → {{ showLogValue(log, log.afterValue) }}
|
||||||
</div>
|
</div>
|
||||||
<div v-if="log.changeQty" class="mt-1">数量变化:{{ log.changeQty > 0 ? '+' : '' }}{{ log.changeQty }}</div>
|
<div v-if="log.changeQty" class="mt-1">数量变化:{{ log.changeQty > 0 ? '+' : '' }}{{ log.changeQty }} 根</div>
|
||||||
<div v-if="log.operationReason" class="mt-1 whitespace-pre-wrap">原因:{{ log.operationReason }}</div>
|
<div v-if="log.operationReason" class="mt-1 whitespace-pre-wrap">原因:{{ log.operationReason }}</div>
|
||||||
</TimelineItem>
|
</TimelineItem>
|
||||||
</Timeline>
|
</Timeline>
|
||||||
|
|||||||
Reference in New Issue
Block a user