#
vincentlu
2025-05-13 ebd2f4397a92c6a5096de1b86d59154363344720
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
import * as React from 'react';
import { useState } from 'react';
import { Paper, Typography, Box, AvatarGroup, Avatar } from '@mui/material';
import {
    useCreatePath,
    useRecordContext,
    Link,
    useResourceContext,
    useDataProvider,
} from 'react-admin';
import PulseSignal from '../components/PulseSignal';
import { AgvAvatar } from './AgvAvatar';
import { red, blue, blueGrey } from '@mui/material/colors';
 
export const AgvCard = (props) => {
    const resource = useResourceContext();
    const [elevation, setElevation] = useState(1);
    const createPath = useCreatePath();
    const record = useRecordContext(props);
    if (!record) return null;
 
    return (
        <Link
            to={createPath({
                resource: resource,
                id: record.id,
                type: 'show',
            })}
            underline="none"
            onMouseEnter={() => setElevation(3)}
            onMouseLeave={() => setElevation(1)}
        >
            <Paper
                sx={{
                    height: 200,
                    display: 'flex',
                    flexDirection: 'column',
                    justifyContent: 'space-between',
                    padding: '1em',
                    ...(!record.online && {
                        animation: 'cardBorderPulse 2s infinite',
                        '@keyframes cardBorderPulse': {
                            '0%': {
                                boxShadow: '0 0 2px 1px rgba(255, 0, 0, 0.1)',
                            },
                            '50%': {
                                boxShadow: '0 0 3px 2px rgba(255, 0, 0, 0.3)',
                            },
                            '100%': {
                                boxShadow: '0 0 2px 1px rgba(255, 0, 0, 0.1)',
                            },
                        },
                    })
                }}
                elevation={elevation}
            >
                <Box display="flex" flexDirection="row" alignItems="center" justifyContent='space-between'>
                    <PulseSignal
                        flag={record.online}
                    />
                    <Typography variant="caption" >
                        vol:
                        <Box
                            component={"span"}
                            sx={{
                                color: record.vol < record.chargeLine ? red[400] : 'inherit'
                            }}>
                            {record.vol}
                        </Box>
                    </Typography>
                </Box>
                <Box display="flex" flexDirection="column" alignItems="center">
                    <AgvAvatar />
                    <Box textAlign="center" marginTop={2}>
                        <Typography
                            variant="subtitle2"
                            color="textSecondary"
                            component="div"
                            sx={{ fontWeight: 'bold' }}
                        >
                            {record.agvStatus}
                        </Typography>
                        <Typography variant="overline" sx={{ opacity: .7 }}>
                            code: {record.code}
                        </Typography>
                    </Box>
                </Box>
                <Box display="flex" justifyContent="space-around" width="100%">
                    <Box display="flex" alignItems="center">
                        <TaskAvatarGroupIterator taskIds={record.taskIds} />
                    </Box>
                </Box>
            </Paper>
        </Link>
    );
};
 
const TaskAvatarGroupIterator = ({ taskIds }) => {
    const dataProvider = useDataProvider();
    const [data, setData] = React.useState([]);
    const [total, setTotal] = React.useState(0);
 
    React.useEffect(() => {
        if (taskIds?.length > 0) {
            dataProvider.getMany('task', { ids: taskIds }).then(res => {
                if (res.data?.length > 0) {
                    setTotal(res.data.length);
                    setData(res.data);
                }
            })
        }
    }, [taskIds])
 
    return (
        <AvatarGroup
            max={4}
            total={total}
            spacing="medium"
            sx={{
                '& .MuiAvatar-circular': {
                    width: 35,
                    height: 25,
                    fontSize: '0.7rem',
                },
            }}
        >
            {data.length > 0 ? (
                data.map((record) => (
                    <Avatar
                        key={record.id}
                        title={`${record.seqNum}`}
                        sx={{ bgcolor: blueGrey[500] }}
                    >
                        {record.seqNum.slice(0, 4)}
                    </Avatar>
                ))
            ) : (
                <Avatar title="No tasks" >
                    N/A
                </Avatar>
            )}
        </AvatarGroup>
    );
}