forked from CITKParus/P8-Panels
169 lines
6.8 KiB
JavaScript
169 lines
6.8 KiB
JavaScript
/*
|
||
Парус 8 - Панели мониторинга - ПУП - Информация о проектах
|
||
Общие дополнительная разметка и вёрстка клиентских элементов
|
||
*/
|
||
|
||
//---------------------
|
||
//Подключение библиотек
|
||
//---------------------
|
||
|
||
import React, { useState, useEffect } from "react"; //Классы React
|
||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||
import { Box, Icon, Input, InputAdornment, FormControl, Select, InputLabel, MenuItem, IconButton, Typography, Switch, Stack } from "@mui/material"; //Интерфейсные компоненты
|
||
|
||
//---------
|
||
//Константы
|
||
//---------
|
||
|
||
//Стили
|
||
const STYLES = {
|
||
STATE: value => ({ color: value === 1 ? "green" : "black" }),
|
||
COST_STATUS: color => ({ color, verticalAlign: "middle" }),
|
||
COST_READY: value => ({ color: value <= 30 ? "red" : value >= 80 ? "green" : "#e2af00" }),
|
||
TOGGLE_COLOR: checked => ({ color: checked ? "#006dd9" : "lightgrey" })
|
||
};
|
||
|
||
//-----------
|
||
//Тело модуля
|
||
//-----------
|
||
|
||
//Поле ввода формы
|
||
const FormField = ({ elementCode, elementValue, labelText, onChange, dictionary, list, type, ...other }) => {
|
||
//Значение элемента
|
||
const [value, setValue] = useState(elementValue);
|
||
|
||
//При получении нового значения из вне
|
||
useEffect(() => {
|
||
setValue(elementValue);
|
||
}, [elementValue]);
|
||
|
||
//Выбор значения из словаря
|
||
const handleDictionaryClick = () =>
|
||
dictionary ? dictionary(res => (res ? res.map(i => handleChange({ target: { name: i.name, value: i.value } })) : null)) : null;
|
||
|
||
//Изменение значения элемента (по событию)
|
||
const handleChange = e => {
|
||
setValue(e.target.value);
|
||
if (onChange) onChange(e.target.name, e.target.value);
|
||
};
|
||
|
||
//Генерация содержимого
|
||
return (
|
||
<Box p={1}>
|
||
<FormControl variant="standard" fullWidth {...other}>
|
||
{list ? (
|
||
<>
|
||
<InputLabel id={`${elementCode}Lable`} shrink>
|
||
{labelText}
|
||
</InputLabel>
|
||
<Select
|
||
labelId={`${elementCode}Lable`}
|
||
id={elementCode}
|
||
name={elementCode}
|
||
label={labelText}
|
||
value={value || value == 0 ? value : ""}
|
||
onChange={handleChange}
|
||
displayEmpty
|
||
>
|
||
{list.map((item, i) => (
|
||
<MenuItem key={i} value={item.value || item.value == 0 ? item.value : ""}>
|
||
{item.name}
|
||
</MenuItem>
|
||
))}
|
||
</Select>
|
||
</>
|
||
) : (
|
||
<>
|
||
<InputLabel {...(type == "date" ? { shrink: true } : {})} htmlFor={elementCode}>
|
||
{labelText}
|
||
</InputLabel>
|
||
<Input
|
||
id={elementCode}
|
||
name={elementCode}
|
||
value={value || value == 0 ? value : ""}
|
||
endAdornment={
|
||
dictionary ? (
|
||
<InputAdornment position="end">
|
||
<IconButton aria-label={`${elementCode} select`} onClick={handleDictionaryClick} edge="end">
|
||
<Icon>list</Icon>
|
||
</IconButton>
|
||
</InputAdornment>
|
||
) : null
|
||
}
|
||
{...(type ? { type } : {})}
|
||
onChange={handleChange}
|
||
/>
|
||
</>
|
||
)}
|
||
</FormControl>
|
||
</Box>
|
||
);
|
||
};
|
||
|
||
//Контроль свойств - Поле ввода формы
|
||
FormField.propTypes = {
|
||
elementCode: PropTypes.string.isRequired,
|
||
elementValue: PropTypes.oneOfType([PropTypes.number, PropTypes.string, PropTypes.instanceOf(Date)]),
|
||
labelText: PropTypes.string.isRequired,
|
||
onChange: PropTypes.func,
|
||
dictionary: PropTypes.func,
|
||
list: PropTypes.array,
|
||
type: PropTypes.string
|
||
};
|
||
|
||
//Переключатель
|
||
const Toggle = ({ labels, checked, onChange }) => {
|
||
//Обработка переключения
|
||
const handleChange = event => (onChange ? onChange(event.target.checked) : null);
|
||
|
||
//Генерация содержимого
|
||
return (
|
||
<Stack direction={"row"} spacing={1} alignItems={"center"} justifyContent={"center"}>
|
||
<Typography sx={STYLES.TOGGLE_COLOR(!checked)}>{labels[0]}</Typography>
|
||
<Switch checked={checked} size="small" onChange={handleChange} />
|
||
<Typography sx={STYLES.TOGGLE_COLOR(checked)}>{labels[1]}</Typography>
|
||
</Stack>
|
||
);
|
||
};
|
||
|
||
//Контроль свойств компонента - Переключатель
|
||
Toggle.propTypes = {
|
||
labels: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||
checked: PropTypes.bool.isRequired,
|
||
onChange: PropTypes.func
|
||
};
|
||
|
||
//Формирование значения для колонки "Статус структуры цены"
|
||
const formatCostStatusValue = ({ value, onClick, type = 1 }) => {
|
||
const [text, color] =
|
||
value == 0
|
||
? ["Без отклонений", "lightgreen"]
|
||
: value == 1
|
||
? [type == 1 ? "Есть статьи с расходом более 90%" : "Расход более 90%", "#ffdf71"]
|
||
: value == 2
|
||
? [type == 1 ? "Есть статьи с перерасходом" : "Перерасход", "#eb6b6b"]
|
||
: ["Не определено", "lightgray"];
|
||
return onClick ? (
|
||
<IconButton onClick={onClick}>
|
||
<Icon sx={STYLES.COST_STATUS(color)} title={`${text}\nНажмите для детальной информации`}>
|
||
circle
|
||
</Icon>
|
||
</IconButton>
|
||
) : (
|
||
<Icon sx={STYLES.COST_STATUS(color)} title={text}>
|
||
circle
|
||
</Icon>
|
||
);
|
||
};
|
||
|
||
//Формирование значения для колонки "Готов (%, зтраты)"
|
||
const formatCostReadyValue = value => {
|
||
return <span style={STYLES.COST_READY(value)}>{value}</span>;
|
||
};
|
||
|
||
//----------------
|
||
//Интерфейс модуля
|
||
//----------------
|
||
|
||
export { STYLES as COMMON_STYLES, FormField, Toggle, formatCostStatusValue, formatCostReadyValue };
|