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 };
 |