chen.lin
昨天 fcf0c2bbfae0a82d516dfa8b71f97e6ea817e0b4
任务管理查询明细修正
4个文件已修改
200 ■■■■■ 已修改文件
rsf-admin/src/page/components/PageDrawer.jsx 30 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/task/TaskList.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/common/domain/PageParam.java 131 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/Task.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/components/PageDrawer.jsx
@@ -23,26 +23,46 @@
        }
    }
    const isOpen = !!drawerVal;
    return (
        <Drawer
            variant="persistent"
            open={!!drawerVal}
            open={isOpen}
            anchor="right"
            onClose={handleClose}
            sx={{
                zIndex: 100,
                '& .MuiDrawer-paper': {
                    top: '86px', // AppBar(50px) + TabsBar(36px)
                    top: '86px', // AppBar(50px) + TabsBar(36px)
                    // 当关闭时,确保内容不可聚焦
                    ...(isOpen ? {} : {
                        pointerEvents: 'none',
                        visibility: 'hidden',
                    })
                }
            }}
            // 对于 persistent Drawer,使用 PaperProps 来控制可访问性
            PaperProps={{
                'aria-hidden': !isOpen,
                tabIndex: isOpen ? 0 : -1,
            }}
        >
            {!!drawerVal && (
                <Box pt={2} width={{ xs: '100vW', sm: width }} mt={{ xs: 2, sm: 1 }}>
            {isOpen && (
                <Box
                    pt={2}
                    width={{ xs: '100vW', sm: width }}
                    mt={{ xs: 2, sm: 1 }}
                >
                    <Stack direction="row" p={2}>
                        <Typography variant="h6" flex="1">
                            {title}
                        </Typography>
                        <IconButton onClick={handleClose} size="small">
                        <IconButton
                            onClick={handleClose}
                            size="small"
                            aria-label="关闭"
                        >
                            <CloseIcon />
                        </IconButton>
                    </Stack>
rsf-admin/src/page/task/TaskList.jsx
@@ -156,7 +156,7 @@
                    rowClick={false}
                    expand={<TaskPanel />}
                    expandSingle={true}
                    omit={['id', 'createTime', 'createBy$', 'memo', 'robotCode', 'exceStatus', 'expDesc', 'expCode', 'status','warehType$']}
                    omit={['id', 'createTime', 'createBy$', 'memo', 'robotCode', 'exceStatus', 'expDesc', 'expCode', 'status','warehType$', 'orderType', 'order_type', 'orderType$']}
                >
                    <NumberField source="id" />
                    <TextField source="taskCode" label="table.field.task.taskCode" />
@@ -164,9 +164,9 @@
                    <NumberField source="taskType$" label="table.field.task.taskType" />
                    <NumberField source="warehType$" label="table.field.task.warehType" />
                    <TextField source="orgLoc" label="table.field.task.orgLoc" />
                    <TextField source="orgSite" label="table.field.task.orgSite" />
                    <TextField source="orgSite$" label="table.field.task.orgSite" />
                    <TextField source="targLoc" label="table.field.task.targLoc" />
                    <TextField source="targSite" label="table.field.task.targSite" />
                    <TextField source="targSite$" label="table.field.task.targSite" />
                    <TextField source="barcode" label="table.field.task.barcode" />
                    <TextField source="robotCode" label="table.field.task.robotCode" />
                    <NumberField source="exceStatus" label="table.field.task.exceStatus" />
rsf-server/src/main/java/com/vincent/rsf/server/common/domain/PageParam.java
@@ -8,7 +8,11 @@
import com.vincent.rsf.framework.common.Cools;
import com.vincent.rsf.framework.common.DateUtils;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*;
@@ -17,6 +21,7 @@
/**
 * Created by vincent on 2/13/2024
 */
@Slf4j
public class PageParam<T, U extends BaseParam> extends Page<T> {
    private static final long serialVersionUID = 1L;
@@ -31,6 +36,11 @@
    private final boolean isToUnderlineCase;
    private final Class<T> cls;
    /**
     * 额外的字段验证类列表(用于支持 DTO、VO 等类的字段验证)
     */
    private List<Class<?>> additionalFieldClasses;
    public PageParam() {
        this(null);
@@ -129,7 +139,13 @@
        if (!Cools.isEmpty(where.getOrderBy())) {
            if (sortIsSQL(where.getOrderBy())) {
                setOrders(parseOrderSQL(where.getOrderBy()));
                List<OrderItem> orders = parseOrderSQL(where.getOrderBy());
                // 如果所有排序字段都无效,使用默认排序
                if (orders.isEmpty()) {
                    queryWrapper.orderByDesc("create_time");
                } else {
                    setOrders(orders);
                }
            }
        } else {
//            queryWrapper.orderByDesc("create_time");
@@ -221,7 +237,13 @@
        if (!Cools.isEmpty(where.getOrderBy())) {
            if (sortIsSQL(where.getOrderBy())) {
                setOrders(parseOrderSQL(where.getOrderBy()));
                List<OrderItem> orders = parseOrderSQL(where.getOrderBy());
                // 如果所有排序字段都无效,使用默认排序
                if (orders.isEmpty()) {
                    queryWrapper.orderByDesc("create_time");
                } else {
                    setOrders(orders);
                }
            }
        } else {
//            queryWrapper.orderByDesc("create_time");
@@ -282,10 +304,21 @@
    private List<OrderItem> parseOrderSQL(String orderSQL) {
        List<OrderItem> orders = new ArrayList<>();
        if (!Cools.isEmpty(orderSQL)) {
            // 获取实体类的有效字段列表
            Set<String> validColumns = getValidColumns();
            for (String item : orderSQL.split(",")) {
                String[] temp = item.trim().split(" ");
                if (!temp[0].isEmpty()) {
                    String column = this.isToUnderlineCase ? Utils.toSymbolCase(temp[0], '_') : temp[0];
                    // 验证字段是否存在,如果不存在则跳过
                    if (validColumns != null && !validColumns.isEmpty() && !validColumns.contains(column)) {
                        // 获取当前请求信息
                        String requestInfo = getRequestInfo();
//                        log.warn("跳过无效的排序字段: '{}' (原始值: '{}'),实体类: {},请求地址: {}",
//                                column, temp[0], cls != null ? cls.getSimpleName() : "null", requestInfo);
                        continue;
                    }
                    boolean asc = temp.length == 1 || !temp[temp.length - 1].toLowerCase().equals(ORDER_DESC_VALUE);
                    orders.add(new OrderItem(column, asc));
                }
@@ -294,6 +327,100 @@
        return orders;
    }
    /**
     * 获取当前请求信息(路径和方法)
     * @return 请求信息字符串,格式:HTTP方法 请求路径
     */
    private String getRequestInfo() {
        try {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes != null) {
                HttpServletRequest request = attributes.getRequest();
                if (request != null) {
                    String method = request.getMethod();
                    String uri = request.getRequestURI();
                    return String.format("%s %s", method, uri);
                }
            }
        } catch (Exception e) {
            // 忽略异常,避免影响主流程
            log.debug("获取请求信息失败: {}", e.getMessage());
        }
        return "未知";
    }
    /**
     * 获取实体类的有效字段列表(用于验证排序字段)
     * 包括:实体类字段、以及额外指定的DTO/VO类字段
     * 注意:BaseParam 的字段是查询参数,不用于数据库字段验证
     */
    private Set<String> getValidColumns() {
        Set<String> columns = new HashSet<>();
        // 1. 获取实体类(cls)的字段
        if (cls != null) {
            addFieldsFromClass(cls, columns);
        }
        // 2. 获取额外指定的类(DTO/VO等)的字段
        if (additionalFieldClasses != null && !additionalFieldClasses.isEmpty()) {
            for (Class<?> clazz : additionalFieldClasses) {
                addFieldsFromClass(clazz, columns);
            }
        }
        return columns.isEmpty() ? null : columns;
    }
    /**
     * 从指定类中提取字段并添加到集合中
     * @param clazz 要提取字段的类
     * @param columns 字段集合
     */
    private void addFieldsFromClass(Class<?> clazz, Set<String> columns) {
        for (Field field : Cools.getAllFields(clazz)) {
            // 跳过 final、static、transient 字段
            if (Modifier.isFinal(field.getModifiers())
                    || Modifier.isStatic(field.getModifiers())
                    || Modifier.isTransient(field.getModifiers())) {
                continue;
            }
            // 跳过标记为 exist=false 的字段(这些字段不存在于数据库中)
            if (field.isAnnotationPresent(TableField.class)) {
                TableField annotation = field.getAnnotation(TableField.class);
                if (!annotation.exist()) {
                    continue;
                }
            }
            String column = Utils.toSymbolCase(field.getName(), '_');
            columns.add(column);
        }
    }
    /**
     * 设置额外的字段验证类列表(用于支持 DTO、VO 等类的字段验证)
     * @param classes 额外的类列表
     * @return 当前实例,支持链式调用
     */
    public PageParam<T, U> setAdditionalFieldClasses(Class<?>... classes) {
        if (classes != null && classes.length > 0) {
            this.additionalFieldClasses = Arrays.asList(classes);
        }
        return this;
    }
    /**
     * 设置额外的字段验证类列表(用于支持 DTO、VO 等类的字段验证)
     * @param classes 额外的类列表
     * @return 当前实例,支持链式调用
     */
    public PageParam<T, U> setAdditionalFieldClasses(List<Class<?>> classes) {
        this.additionalFieldClasses = classes;
        return this;
    }
    public Map<String, Object> checkoutMap() {
        Map<String, Object> map = where.getMap();
        if (!Cools.isEmpty(where.getOrderBy())) {
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/Task.java
@@ -34,7 +34,7 @@
import java.io.Serializable;
import java.util.Date;
import java.util.stream.Collectors;
import com.vincent.rsf.server.manager.service.BasStationService;
@Data
@Accessors(chain = true)
@TableName("man_task")
@@ -390,5 +390,36 @@
                return null;
        }
    }
    /**
     * 获取源站点名称(站点编号 + 站点名称)
     */
    public String getOrgSite$(){
        if (Cools.isEmpty(this.orgSite)) {
            return this.orgSite;
        }
        BasStationService basStationService = SpringUtils.getBean(BasStationService.class);
        BasStation station = basStationService.getOne(new LambdaQueryWrapper<BasStation>()
                .eq(BasStation::getStationName, this.orgSite));
        if (!Cools.isEmpty(station) && !Cools.isEmpty(station.getStationId())) {
            return this.orgSite + "(" + station.getStationId() + ")";
        }
        return this.orgSite;
    }
    /**
     * 获取目标站点名称(站点编号 + 站点名称)
     */
    public String getTargSite$(){
        if (Cools.isEmpty(this.targSite)) {
            return this.targSite;
        }
        BasStationService basStationService = SpringUtils.getBean(BasStationService.class);
        BasStation station = basStationService.getOne(new LambdaQueryWrapper<BasStation>()
                .eq(BasStation::getStationName, this.targSite));
        if (!Cools.isEmpty(station) && !Cools.isEmpty(station.getStationId())) {
            return this.targSite + "(" + station.getStationId() + ")";
        }
        return this.targSite;
    }
}