#
vincentlu
昨天 10492a922d3a8d295ada4ec99cc928031f3abd0e
#
1个文件已添加
8个文件已修改
670 ■■■■ 已修改文件
zy-acs-common/src/main/java/com/zy/acs/common/utils/News.java 193 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/i18n/en.js 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/i18n/zh.js 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/map/MapPage.jsx 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/map/NewsLogDialog.jsx 420 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-flow/src/map/http.js 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-manager/src/main/java/com/zy/acs/manager/common/CodeBuilder.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-manager/src/main/java/com/zy/acs/manager/core/controller/NewsController.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-manager/src/main/java/com/zy/acs/manager/core/service/TrafficService.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-common/src/main/java/com/zy/acs/common/utils/News.java
@@ -1,10 +1,16 @@
package com.zy.acs.common.utils;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.helpers.FormattingTuple;
import org.slf4j.helpers.MessageFormatter;
import java.lang.reflect.Array;
import java.text.SimpleDateFormat;
import java.util.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * news stories for vincent
@@ -13,85 +19,15 @@
@Slf4j
public class News {
    private static final int DEFAULT_CAPACITY = 1024;
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    private static final NewsQueue<NewsDomain> NEWS_QUEUE = new NewsQueue<>(DEFAULT_CAPACITY);
    public static void main(String[] args) {
        News.info("info{}", 1);
        News.warn("warn{}", 2);
        News.error("error{}", 3);
        System.out.println(News.print());
    }
    interface NewsSupport<T> { boolean execute(T t); }
    private static final NewsQueue<NewsDomain> NEWS_QUEUE = new NewsQueue<>(NewsDomain.class, 1024);
    @SuppressWarnings({"unchecked"})
    static class NewsQueue<T> {
        private final transient Class<T> cls;
        private final T[] arr;
        private final int capacity;
        private int head;
        private int tail;
        { this.head = 0; this.tail = 0; }
        public NewsQueue(Class<T> cls, int capacity) {
            this.cls = cls;
            this.arr = (T[]) Array.newInstance(cls, capacity);
            this.capacity = capacity;
        }
        public synchronized boolean offer(T t) {
            if (this.tail == this.capacity) {
                this.peek();
            }
            this.reform();
            this.arr[this.tail] = t;
            this.tail ++;
            return true;
        }
        public synchronized boolean put(T t) {
            if (this.tail == this.capacity) {
                return false;
            } else {
                this.reform();
            }
            this.arr[this.tail] = t;
            this.tail ++;
            return true;
        }
        public synchronized T peek() {
            if (this.head == this.tail) {
                return null;
            }
            T t = this.arr[this.head];
            this.head ++;
            this.reform();
            return t;
        }
        private void reform() {
            for (int i = this.head; i < this.tail; i++) {
                this.arr[i-this.head] = this.arr[i];
            }
            this.tail -= this.head;
            this.head = 0;
        }
        public synchronized int size() {
            return this.tail - this.head;
        }
        public synchronized List<T> data() {
            T[] ts = (T[]) Array.newInstance(this.cls, size());
            if (this.tail - this.head >= 0) {
                System.arraycopy(this.arr, this.head, ts, 0, this.tail - this.head);
            }
            return Arrays.asList(ts);
        }
    }
    public static void info(String format, Object... arguments) {
@@ -115,9 +51,9 @@
        for (int i = 0; i < domains.size(); i++) {
            NewsDomain domain = domains.get(i);
            sb.append("{");
            sb.append("\"l\":").append(domain.level.idx).append(",");
            sb.append("\"v\":\"").append(domain.content).append("\"").append(",");
            sb.append("\"t\":\"").append(domain.date).append("\"");
            sb.append("\"l\":").append(domain.getLevel().idx).append(",");
            sb.append("\"v\":\"").append(escapeJson(domain.getContent())).append("\"").append(",");
            sb.append("\"t\":\"").append(escapeJson(domain.getDate())).append("\"");
            sb.append("}");
            if (i < domains.size() - 1) {
                sb.append(",");
@@ -131,42 +67,107 @@
        List<Map<String, Object>> res = new ArrayList<>();
        for (NewsDomain datum : NEWS_QUEUE.data()) {
            Map<String, Object> map = new HashMap<>();
            map.put("l", datum.level.idx);
            map.put("v", datum.content);
            map.put("t", datum.date);
            map.put("l", datum.getLevel().idx);
            map.put("v", datum.getContent());
            map.put("t", datum.getDate());
            res.add(map);
        }
        return res;
    }
    private static boolean offer(NewsLevel level, String msg, Object[] args) {
        return NEWS_QUEUE.offer(new NewsDomain(level, replace(msg, args), (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")).format(new Date())));
        String template = msg == null ? "" : msg;
        FormattingTuple tuple = MessageFormatter.arrayFormat(template, args);
        String formatted = tuple.getMessage();
        return NEWS_QUEUE.offer(new NewsDomain(level, formatted,
                LocalDateTime.now().format(DATE_FORMATTER)));
    }
    private static String replace(String str, Object[] objs){
        if (null == objs || objs.length == 0 || null == str || "".equals(str.trim())) {
            return str;
    private static String escapeJson(String value) {
        if (value == null) {
            return "";
        }
        StringBuilder sb = new StringBuilder(value.length());
        for (char c : value.toCharArray()) {
            switch (c) {
                case '"':
                    sb.append("\\\"");
                    break;
                case '\\':
                    sb.append("\\\\");
                    break;
                case '\n':
                    sb.append("\\n");
                    break;
                case '\r':
                    sb.append("\\r");
                    break;
                case '\t':
                    sb.append("\\t");
                    break;
                default:
                    if (c < 0x20) {
                        sb.append(String.format("\\u%04x", (int) c));
        } else {
            StringBuilder sb = new StringBuilder(str);
            for (Object obj : objs) {
                int idx = sb.indexOf("{}");
                if (idx == -1) { break; }
                sb.replace(idx, idx + 2, String.valueOf(obj));
                        sb.append(c);
                    }
            }
            }
            return sb.toString();
        }
    private static final class NewsQueue<T> {
        private final Object[] arr;
        private final int capacity;
        private int head;
        private int size;
        private NewsQueue(int capacity) {
            if (capacity <= 0) {
                throw new IllegalArgumentException("capacity must be > 0");
            }
            this.arr = new Object[capacity];
            this.capacity = capacity;
            this.head = 0;
            this.size = 0;
    }
        public synchronized boolean offer(T t) {
            int writeIndex = (head + size) % capacity;
            arr[writeIndex] = t;
            if (size == capacity) {
                head = (head + 1) % capacity;
            } else {
                size++;
            }
            return true;
        }
        public synchronized List<T> data() {
            List<T> copy = new ArrayList<>(size);
            for (int i = 0; i < size; i++) {
                int idx = (head + i) % capacity;
                @SuppressWarnings("unchecked")
                T element = (T) arr[idx];
                copy.add(element);
            }
            return copy;
        }
    }
    @Data
    static class NewsDomain {
        public NewsLevel level;
        public String content;
        public String date;
        private final NewsLevel level;
        private final String content;
        private final String date;
        public NewsDomain(NewsLevel level, String content, String date) {
            this.level = level;
            this.content = content;
            this.date = date;
        }
    }
    enum NewsLevel {
@@ -174,7 +175,7 @@
        WARN(2),
        ERROR(3),
        ;
        public int idx;
        public final int idx;
        NewsLevel(int idx) {
            this.idx = idx;
        }
zy-acs-flow/src/i18n/en.js
@@ -875,6 +875,17 @@
        },
        map: {
            welcome: 'Welcome to the RCS System. Tip: Left-click to select objects, right-click to pan the view, and use the scroll wheel to zoom the view.',
            monitor: {
                log: {
                    title: 'Real-time Logs',
                    autoScroll: 'Auto Scroll',
                    empty: 'No Logs',
                    jumpLatest: 'Jump to latest',
                    lastUpdate: {
                        empty: 'No Updates',
                    },
                },
            },
            devices: {
                title: 'Icons',
                shelf: 'SHELF',
zy-acs-flow/src/i18n/zh.js
@@ -875,6 +875,17 @@
        },
        map: {
            welcome: '欢迎使用 RCS 系统。提示:鼠标左键选中对象,右键平移视图,滚轮缩放视图。',
            monitor: {
                log: {
                    title: '日志监控',
                    autoScroll: '自动滚动',
                    empty: '暂无日志',
                    jumpLatest: '回到最新',
                    lastUpdate: {
                        empty: '暂无更新',
                    },
                },
            },
            devices: {
                title: '图标库',
                shelf: '货架',
zy-acs-flow/src/map/MapPage.jsx
@@ -29,6 +29,7 @@
import RouteFab from "./header/RouteFab";
import AreaFab from "./header/AreaFab";
import MoreOperate from "./header/MoreOperate";
import NewsLogDialog from "./NewsLogDialog";
let player;
let websocket;
@@ -66,6 +67,7 @@
        const storedValue = localStorage.getItem('curZone');
        return storedValue !== null ? JSON.parse(storedValue) : null;
    });
    const [logDialogOpen, setLogDialogOpen] = useState(false);
    const handleResize = () => {
        if (!contentRef.current || !player) {
@@ -315,7 +317,11 @@
                        >
                            {rcsStatus ? translate('page.map.action.shutdown') : translate('page.map.action.startup')}
                        </Button>
                        <Button variant="contained" color="primary">
                        <Button
                            variant="contained"
                            color="primary"
                            onClick={() => setLogDialogOpen(true)}
                        >
                            {translate('page.map.action.monitor')}
                        </Button>
                        <MoreOperate />
@@ -592,6 +598,10 @@
                width={378}
            />
            <NewsLogDialog
                open={logDialogOpen}
                onClose={() => setLogDialogOpen(false)}
            />
        </Box>
    );
}
zy-acs-flow/src/map/NewsLogDialog.jsx
New file
@@ -0,0 +1,420 @@
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import {
    Box,
    Button,
    Chip,
    Divider,
    FormControlLabel,
    IconButton,
    Paper,
    Stack,
    Switch,
    Typography,
    useTheme,
} from '@mui/material';
import CloseIcon from '@mui/icons-material/Close';
import PushPinIcon from '@mui/icons-material/PushPin';
import { useTranslate } from 'react-admin';
import * as Http from './http';
const LOG_LEVEL_META = {
    1: { label: 'INFO', color: 'info' },
    2: { label: 'WARN', color: 'warning' },
    3: { label: 'ERROR', color: 'error' },
};
const POLLING_INTERVAL = 2000;
const PANEL_WIDTH = 480;
const PANEL_HEIGHT = 360;
const MIN_WIDTH = 320;
const MIN_HEIGHT = 240;
const EDGE_MARGIN = 16;
const clamp = (value, min, max) => Math.min(Math.max(value, min), max);
const NewsLogDialog = ({ open, onClose }) => {
    const translate = useTranslate();
    const theme = useTheme();
    const [logs, setLogs] = useState([]);
    const [autoScroll, setAutoScroll] = useState(true);
    const [lastUpdated, setLastUpdated] = useState(null);
    const [position, setPosition] = useState(null);
    const [size, setSize] = useState(null);
    const scrollRef = useRef(null);
    const panelRef = useRef(null);
    const pollingRef = useRef(null);
    const dragRef = useRef({ active: false, offsetX: 0, offsetY: 0 });
    const resizeRef = useRef({
        active: false,
        startX: 0,
        startY: 0,
        initialWidth: PANEL_WIDTH,
        initialHeight: PANEL_HEIGHT,
        initialX: EDGE_MARGIN,
        initialY: EDGE_MARGIN,
    });
    const getSizeLimits = useCallback(() => {
        const viewportWidth = typeof window === 'undefined' ? PANEL_WIDTH + 64 : window.innerWidth;
        const viewportHeight = typeof window === 'undefined' ? PANEL_HEIGHT + 160 : window.innerHeight;
        return {
            maxWidth: Math.max(MIN_WIDTH, viewportWidth - 64),
            maxHeight: Math.max(MIN_HEIGHT, viewportHeight - 160),
        };
    }, []);
    const buildInitialSize = useCallback(() => {
        const { maxWidth, maxHeight } = getSizeLimits();
        return {
            width: clamp(PANEL_WIDTH, MIN_WIDTH, maxWidth),
            height: clamp(PANEL_HEIGHT, MIN_HEIGHT, maxHeight),
        };
    }, [getSizeLimits]);
    const fetchLogs = useCallback(async () => {
        const data = await Http.fetchNewsLogs();
        if (Array.isArray(data)) {
            setLogs(data);
            setLastUpdated(new Date());
        }
    }, []);
    useEffect(() => {
        if (!open) {
            clearInterval(pollingRef.current);
            pollingRef.current = null;
            setLogs([]);
            setLastUpdated(null);
            setPosition(null);
            setSize(null);
            return;
        }
        setSize(buildInitialSize());
        setAutoScroll(true);
        fetchLogs();
        pollingRef.current = setInterval(fetchLogs, POLLING_INTERVAL);
        return () => {
            clearInterval(pollingRef.current);
            pollingRef.current = null;
        };
    }, [open, fetchLogs, buildInitialSize]);
    useEffect(() => {
        if (!autoScroll || !scrollRef.current) {
            return;
        }
        scrollRef.current.scrollTo({
            top: scrollRef.current.scrollHeight,
            behavior: 'smooth',
        });
    }, [logs, autoScroll]);
    const handleScroll = useCallback(() => {
        if (!scrollRef.current || !autoScroll) {
            return;
        }
        const { scrollTop, scrollHeight, clientHeight } = scrollRef.current;
        if (scrollHeight - (scrollTop + clientHeight) > 32) {
            setAutoScroll(false);
        }
    }, [autoScroll]);
    const handleJumpLatest = () => {
        setAutoScroll(true);
        if (scrollRef.current) {
            scrollRef.current.scrollTo({
                top: scrollRef.current.scrollHeight,
                behavior: 'smooth',
            });
        }
    };
    const handleClose = () => {
        onClose?.();
    };
    const handleDragging = useCallback((event) => {
        if (!dragRef.current.active) {
            return;
        }
        event.preventDefault();
        const width = panelRef.current?.offsetWidth || PANEL_WIDTH;
        const height = panelRef.current?.offsetHeight || PANEL_HEIGHT;
        const viewportWidth = typeof window === 'undefined' ? width + 2 * EDGE_MARGIN : window.innerWidth;
        const viewportHeight = typeof window === 'undefined' ? height + 10 * EDGE_MARGIN : window.innerHeight;
        const maxX = viewportWidth - width - EDGE_MARGIN;
        const maxY = viewportHeight - height - EDGE_MARGIN;
        const x = event.clientX - dragRef.current.offsetX;
        const y = event.clientY - dragRef.current.offsetY;
        setPosition({
            x: clamp(x, EDGE_MARGIN, Math.max(maxX, EDGE_MARGIN)),
            y: clamp(y, EDGE_MARGIN, Math.max(maxY, EDGE_MARGIN)),
        });
    }, []);
    const handleDragEnd = useCallback(() => {
        if (!dragRef.current.active) {
            return;
        }
        dragRef.current.active = false;
        document.removeEventListener('mousemove', handleDragging);
        document.removeEventListener('mouseup', handleDragEnd);
    }, [handleDragging]);
    const handleDragStart = useCallback((event) => {
        if (!panelRef.current) {
            return;
        }
        const rect = panelRef.current.getBoundingClientRect();
        dragRef.current = {
            active: true,
            offsetX: event.clientX - rect.left,
            offsetY: event.clientY - rect.top,
        };
        document.addEventListener('mousemove', handleDragging);
        document.addEventListener('mouseup', handleDragEnd);
    }, [handleDragging, handleDragEnd]);
    const handleResizing = useCallback((event) => {
        if (!resizeRef.current.active) {
            return;
        }
        event.preventDefault();
        const deltaX = event.clientX - resizeRef.current.startX;
        const deltaY = event.clientY - resizeRef.current.startY;
        const { maxWidth, maxHeight } = getSizeLimits();
        const initialWidth = resizeRef.current.initialWidth;
        const initialHeight = resizeRef.current.initialHeight;
        const initialX = resizeRef.current.initialX;
        const initialY = resizeRef.current.initialY;
        const initialRight = initialX + initialWidth;
        const maxWidthAllowed = Math.min(maxWidth, initialRight - EDGE_MARGIN);
        const widthRaw = initialWidth - deltaX;
        const newWidth = clamp(widthRaw, MIN_WIDTH, Math.max(MIN_WIDTH, maxWidthAllowed));
        const newX = clamp(initialRight - newWidth, EDGE_MARGIN, Math.max(initialRight - MIN_WIDTH, EDGE_MARGIN));
        const newHeight = clamp(initialHeight + deltaY, MIN_HEIGHT, maxHeight);
        setSize({
            width: newWidth,
            height: newHeight,
        });
        setPosition({
            x: newX,
            y: initialY,
        });
    }, [getSizeLimits]);
    const handleResizeEnd = useCallback(() => {
        if (!resizeRef.current.active) {
            return;
        }
        resizeRef.current.active = false;
        document.removeEventListener('mousemove', handleResizing);
        document.removeEventListener('mouseup', handleResizeEnd);
    }, [handleResizing]);
    const handleResizeStart = useCallback((event) => {
        event.preventDefault();
        resizeRef.current.active = true;
        resizeRef.current.startX = event.clientX;
        resizeRef.current.startY = event.clientY;
        const rect = panelRef.current?.getBoundingClientRect();
        const resolvedX = position?.x ?? rect?.left ?? EDGE_MARGIN;
        const resolvedY = position?.y ?? rect?.top ?? EDGE_MARGIN;
        resizeRef.current.initialWidth = panelRef.current?.offsetWidth || size?.width || PANEL_WIDTH;
        resizeRef.current.initialHeight = panelRef.current?.offsetHeight || size?.height || PANEL_HEIGHT;
        resizeRef.current.initialX = resolvedX;
        resizeRef.current.initialY = resolvedY;
        setPosition({ x: resolvedX, y: resolvedY });
        document.addEventListener('mousemove', handleResizing);
        document.addEventListener('mouseup', handleResizeEnd);
    }, [handleResizing, handleResizeEnd, size, position]);
    useEffect(() => {
        return () => {
            document.removeEventListener('mousemove', handleDragging);
            document.removeEventListener('mouseup', handleDragEnd);
            document.removeEventListener('mousemove', handleResizing);
            document.removeEventListener('mouseup', handleResizeEnd);
        };
    }, [handleDragging, handleDragEnd, handleResizing, handleResizeEnd]);
    const timeLabel = useMemo(() => {
        if (!lastUpdated) {
            return translate('page.map.monitor.log.lastUpdate.empty', { _: 'No Updates' });
        }
        return lastUpdated.toLocaleTimeString();
    }, [lastUpdated, translate]);
    const panelPositionStyle = position
        ? { top: position.y, left: position.x }
        : { top: 140, right: 24 };
    if (!open) {
        return null;
    }
    const panelWidth = size?.width ?? PANEL_WIDTH;
    const panelHeight = size?.height ?? PANEL_HEIGHT;
    return (
        <Box
            sx={{
                position: 'fixed',
                zIndex: theme.zIndex.drawer + 10,
                pointerEvents: 'none',
                ...panelPositionStyle,
            }}
        >
            <Paper
                ref={panelRef}
                elevation={16}
                sx={{
                    width: panelWidth,
                    height: panelHeight,
                    minWidth: MIN_WIDTH,
                    minHeight: MIN_HEIGHT,
                    display: 'flex',
                    flexDirection: 'column',
                    borderRadius: 2,
                    overflow: 'hidden',
                    pointerEvents: 'auto',
                    backdropFilter: 'blur(4px)',
                    position: 'relative',
                }}
            >
                <Box
                    sx={{
                        display: 'flex',
                        alignItems: 'center',
                        padding: '12px 16px',
                        borderBottom: `1px solid ${theme.palette.divider}`,
                        cursor: 'move',
                        background: theme.palette.mode === 'light'
                            ? theme.palette.grey[50]
                            : theme.palette.grey[900],
                    }}
                    onMouseDown={handleDragStart}
                >
                    <Stack direction="row" spacing={1} alignItems="center">
                        <PushPinIcon fontSize="small" color="primary" />
                        <Typography variant="subtitle1" fontWeight={600}>
                            {translate('page.map.monitor.log.title', { _: 'Real-time Logs' })}
                        </Typography>
                    </Stack>
                    <Box sx={{ flexGrow: 1 }} />
                    <FormControlLabel
                        sx={{ mr: 2, userSelect: 'none' }}
                        control={(
                            <Switch
                                size="small"
                                checked={autoScroll}
                                onChange={(event) => setAutoScroll(event.target.checked)}
                            />
                        )}
                        label={translate('page.map.monitor.log.autoScroll', { _: 'Auto Scroll' })}
                    />
                    <Chip
                        label={timeLabel}
                        size="small"
                        color="primary"
                        variant="outlined"
                        sx={{ mr: 1, fontWeight: 500 }}
                    />
                    <IconButton size="small" onClick={handleClose}>
                        <CloseIcon fontSize="small" />
                    </IconButton>
                </Box>
                <Box
                    ref={scrollRef}
                    onScroll={handleScroll}
                    sx={{
                        flex: 1,
                        minHeight: 0,
                        overflowY: 'auto',
                        px: 3,
                        py: 2,
                        backgroundColor: theme.palette.background.default,
                    }}
                >
                    {logs.length === 0 ? (
                        <Typography variant="body2" color="text.secondary" sx={{ textAlign: 'center', py: 6 }}>
                            {translate('page.map.monitor.log.empty', { _: 'No Logs' })}
                        </Typography>
                    ) : (
                        <Stack spacing={1.25}>
                            {logs.map((item, index) => {
                                const level = item?.l;
                                const levelMeta = LOG_LEVEL_META[level] || LOG_LEVEL_META[1];
                                return (
                                    <Box
                                        key={`${item?.t}-${index}`}
                                        sx={{
                                            borderRadius: 1.5,
                                            border: `1px solid ${theme.palette.divider}`,
                                            backgroundColor: theme.palette.background.paper,
                                            px: 2,
                                            py: 1.25,
                                        }}
                                    >
                                        <Stack direction="row" spacing={1} alignItems="center">
                                            <Chip
                                                label={levelMeta.label}
                                                size="small"
                                                color={levelMeta.color}
                                                variant="outlined"
                                            />
                                            <Divider orientation="vertical" flexItem />
                                            <Typography variant="caption" color="text.secondary">
                                                {item?.t || '--'}
                                            </Typography>
                                        </Stack>
                                        <Typography variant="body2" sx={{ mt: 1, whiteSpace: 'pre-wrap' }}>
                                            {item?.v || ''}
                                        </Typography>
                                    </Box>
                                );
                            })}
                        </Stack>
                    )}
                </Box>
                <Divider />
                <Box
                    sx={{
                        display: 'flex',
                        alignItems: 'center',
                        justifyContent: 'space-between',
                        py: 1,
                        px: 2,
                        backgroundColor: theme.palette.background.paper,
                    }}
                >
                    {!autoScroll && logs.length > 0 ? (
                        <Button onClick={handleJumpLatest} size="small">
                            {translate('page.map.monitor.log.jumpLatest', { _: 'Jump to latest' })}
                        </Button>
                    ) : (
                        <span />
                    )}
                        <Button onClick={handleClose} size="small">
                        {translate('ra.action.close', { _: 'ra.action.close' })}
                    </Button>
                </Box>
                <Box
                    onMouseDown={handleResizeStart}
                    sx={{
                        position: 'absolute',
                        width: 18,
                        height: 18,
                        left: 6,
                        bottom: 6,
                        cursor: 'nesw-resize',
                        borderLeft: `2px solid ${theme.palette.divider}`,
                        borderBottom: `2px solid ${theme.palette.divider}`,
                        borderBottomLeftRadius: 2,
                    }}
                />
            </Paper>
        </Box>
    );
};
export default NewsLogDialog;
zy-acs-flow/src/map/http.js
@@ -497,3 +497,18 @@
    }
    return [];
}
export const fetchNewsLogs = async () => {
    try {
        const res = await request.get('/news/print');
        const { code, msg, data } = res.data;
        if (code === 200) {
            return Array.isArray(data) ? data : [];
        }
        notify?.error(msg);
    } catch (error) {
        notify?.error(error.message);
        console.error(error.message);
    }
    return null;
}
zy-acs-manager/src/main/java/com/zy/acs/manager/common/CodeBuilder.java
@@ -49,7 +49,6 @@
/**
 *
  # dual
  TRUNCATE man_bus;
  TRUNCATE man_task;
  TRUNCATE man_travel;
@@ -62,7 +61,6 @@
  TRUNCATE man_veh_fault_rec;
  # log
  TRUNCATE man_bus_log;
  TRUNCATE man_jam_log;
  TRUNCATE man_lane;
@@ -73,7 +71,6 @@
  TRUNCATE man_action_log;
  # init
  TRUNCATE man_code;
  TRUNCATE man_code_gap;
  TRUNCATE man_route;
zy-acs-manager/src/main/java/com/zy/acs/manager/core/controller/NewsController.java
@@ -11,7 +11,7 @@
 */
@Slf4j
@RestController
@RequestMapping("/news")
@RequestMapping("/api/news")
public class NewsController {
    @RequestMapping("/print")
zy-acs-manager/src/main/java/com/zy/acs/manager/core/service/TrafficService.java
@@ -2,6 +2,7 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zy.acs.common.utils.GsonUtils;
import com.zy.acs.common.utils.News;
import com.zy.acs.common.utils.Utils;
import com.zy.acs.framework.common.Cools;
import com.zy.acs.framework.common.SnowflakeIdWorker;
@@ -337,7 +338,7 @@
                    boolean hasUnavoidableBlocks = blockVehicleList.stream().anyMatch(blockVehicleDto -> !blockVehicleDto.isAvoidable());
                    if (hasUnavoidableBlocks && pathList.size() <= MapDataConstant.MIN_SLICE_PATH_LENGTH) {
                        log.info("AGV[{}] waiting in place, because the path list is too short...", agvNo);
                        News.info("AGV[{}] waiting in place, because the path list is too short...", agvNo);
                        pathList.clear();
                    }