WEBAPP: Поддержка пересчёта диалогов для P8PDialog и P8PInput

This commit is contained in:
Mikhail Chechnev 2025-09-25 14:06:44 +03:00
parent c66216e47b
commit dae416cd83
2 changed files with 43 additions and 25 deletions

View File

@ -26,20 +26,36 @@ const P8P_DIALOG_WIDTH = {
XL: "xl"
};
//-----------------------
//Вспомогательные функции
//-----------------------
//Формирование объекта вида {ключ: значение} из текущего состояния элементов ввода формы
const buildFormValues = inputsState =>
inputsState.reduce((res, input) => ({ ...res, [input.name]: input.value == undefined ? null : input.value }), {});
//-----------
//Тело модуля
//-----------
//Диалог
const P8PDialog = ({ title, width, fullWidth, inputs = [], children, onOk, onCancel, onClose }) => {
//Состояние диалога
const [state, setState] = useState({});
const P8PDialog = ({ title, width, fullWidth, inputs, children, onOk, onCancel, onClose, onInputChange }) => {
//Состояние элементов ввода диалога
const [inputsState, setInputsState] = useState([]);
//При изменении элемента ввода
const handleInputChange = (name, value) => setState(pv => ({ ...pv, [name]: value }));
const handleInputChange = (name, value) => {
//Если есть функция пересчета формы - вызовем её
const doNotChangeInputsState = onInputChange ? onInputChange(name, value, inputsState) : false;
//И ориентируясь на то, пересчитала ли она элементы ввода обновим собственное состояние.
//Если функция пересчета вернула "true", значит она пересчитала что-то, тогда новые настройки элементов придут через свойство inputs и будут обработаны в useEffect ниже.
//Следовательно, и нам здесь не надо состояние выставлять, т.к. всё будет перезаписано useEffectом.
if (!doNotChangeInputsState)
setInputsState(pv => pv.reduce((accum, cur) => [...accum, { ...cur, value: cur.name === name ? value : cur.value }], []));
};
//При нажатии на "ОК" диалога
const handleOk = () => onOk && onOk(state);
const handleOk = () => onOk && onOk(buildFormValues(inputsState));
//При нажатии на "Отмена" диалога
const handleCancel = () => onCancel && onCancel();
@ -47,20 +63,23 @@ const P8PDialog = ({ title, width, fullWidth, inputs = [], children, onOk, onCan
//При нажатии на "Закрыть" диалога
const handleClose = () => (onClose ? onClose() : onCancel ? onCancel() : null);
//При подключении к старнице
//При изменении полей для ввода
useEffect(() => {
setState(inputs.reduce((res, input) => ({ ...res, [input.name]: input.value == undefined ? null : input.value }), {}));
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
if (inputs && Array.isArray(inputs) && inputs.length > 0) setInputsState(inputs.map(input => ({ ...input })));
}, [inputs]);
//Расчет объектного представления текущих значений формы
const formValues = buildFormValues(inputsState);
//Формирование представления
return (
<Dialog onClose={handleClose} open {...{ ...(width ? { maxWidth: width } : {}), ...(fullWidth === true ? { fullWidth: true } : {}) }}>
<DialogTitle>{title}</DialogTitle>
<DialogContent>
{inputs.map((input, i) => (
<P8PInput key={i} {...input} value={state[input.name]} formValues={state} onChange={handleInputChange} />
{inputsState.map((input, i) => (
<P8PInput key={i} {...input} formValues={formValues} onChange={handleInputChange} />
))}
{children}
</DialogContent>
<DialogActions>
@ -81,7 +100,8 @@ P8PDialog.propTypes = {
children: PropTypes.oneOfType([PropTypes.node, PropTypes.arrayOf(PropTypes.node)]),
onOk: PropTypes.func,
onCancel: PropTypes.func,
onClose: PropTypes.func
onClose: PropTypes.func,
onInputChange: PropTypes.func
};
//----------------

View File

@ -35,26 +35,24 @@ const P8P_INPUT = {
//Поле ввода
const P8PInput = ({ name, value, label, onChange, dictionary, list, type, freeSolo = false, disabled = false, formValues, ...other }) => {
//Значение элемента
const [currentValue, setCurrentValue] = useState(value);
//Значение и тип элемента
const [current, setCurrent] = useState({ type: undefined, value: "" });
//При получении нового значения из вне
useEffect(() => {
setCurrentValue(value);
}, [value]);
//При получении нового значения или типа из вне
useEffect(() => setCurrent({ value, type }), [type, value]);
//Выбор значения из словаря
const handleDictionaryClick = () => dictionary && dictionary(formValues, res => (res ? res.map(i => handleChangeByName(i.name, i.value)) : null));
//Изменение значения элемента (по событию)
const handleChange = e => {
setCurrentValue(e.target.value);
setCurrent(pv => ({ ...pv, value: e.target.value }));
if (onChange) onChange(e.target.name, e.target.value);
};
//Изменение значения элемента (по имени и значению)
const handleChangeByName = (targetName, value) => {
if (targetName === name) setCurrentValue(value);
if (targetName === name) setCurrent(pv => ({ ...pv, value }));
if (onChange) onChange(targetName, value);
};
@ -69,7 +67,7 @@ const P8PInput = ({ name, value, label, onChange, dictionary, list, type, freeSo
name={name}
freeSolo
disabled={disabled}
inputValue={currentValue ? currentValue : ""}
inputValue={current.value ? current.value : ""}
onChange={(event, newValue) => handleChangeByName(name, newValue)}
onInputChange={(event, newInputValue) => handleChangeByName(name, newInputValue)}
options={list}
@ -85,7 +83,7 @@ const P8PInput = ({ name, value, label, onChange, dictionary, list, type, freeSo
id={name}
name={name}
label={label}
value={[undefined, null].includes(currentValue) ? "" : currentValue}
value={[undefined, null].includes(current.value) ? "" : current.value}
onChange={handleChange}
disabled={disabled}
displayEmpty
@ -100,13 +98,13 @@ const P8PInput = ({ name, value, label, onChange, dictionary, list, type, freeSo
)
) : (
<>
<InputLabel {...(type == "date" ? { shrink: true } : {})} htmlFor={name}>
<InputLabel {...(current.type == "date" ? { shrink: true } : {})} htmlFor={name}>
{label}
</InputLabel>
<Input
id={name}
name={name}
value={currentValue ? currentValue : ""}
value={current.value ? current.value : ""}
endAdornment={
dictionary ? (
<InputAdornment position="end">
@ -116,7 +114,7 @@ const P8PInput = ({ name, value, label, onChange, dictionary, list, type, freeSo
</InputAdornment>
) : null
}
{...(type ? { type } : {})}
{...(current.type ? { type: current.type } : {})}
onChange={handleChange}
disabled={disabled}
/>