From 6a589020696ec965148606cb10a3db5f7382873e Mon Sep 17 00:00:00 2001 From: Dollerino Date: Fri, 31 Oct 2025 19:14:20 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A6=D0=98=D0=A2=D0=9A-1002=20-=20=D0=BF?= =?UTF-8?q?=D0=B0=D0=BD=D0=B5=D0=BB=D1=8C=20"=D0=94=D0=BE=D1=81=D0=BA?= =?UTF-8?q?=D0=B8=20=D0=B7=D0=B0=D0=B4=D0=B0=D1=87",=20=D0=BE=D0=B1=D1=80?= =?UTF-8?q?=D0=B0=D0=B1=D0=BE=D1=82=D0=BA=D0=B0=20=D0=B0=D0=BD=D0=BD=D1=83?= =?UTF-8?q?=D0=BB=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=BD=D1=8B=D1=85=20?= =?UTF-8?q?=D1=81=D0=BE=D0=B1=D1=8B=D1=82=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../clnt_task_board/components/task_card.js | 43 +++++---- .../clnt_task_board/components/task_form.js | 29 ++---- .../components/task_form_tab_info.js | 10 +- .../components/task_form_tab_props.js | 4 +- .../hooks/task_dialog_hooks.js | 1 + .../clnt_task_board/hooks/tasks_hooks.js | 1 + app/panels/clnt_task_board/layouts.js | 9 ++ app/panels/clnt_task_board/task_dialog.js | 93 ++++++++++++------- db/PKG_P8PANELS_CLNTTSKBRD.pck | 1 + 9 files changed, 109 insertions(+), 82 deletions(-) diff --git a/app/panels/clnt_task_board/components/task_card.js b/app/panels/clnt_task_board/components/task_card.js index 4b69c66..cbe6642 100644 --- a/app/panels/clnt_task_board/components/task_card.js +++ b/app/panels/clnt_task_board/components/task_card.js @@ -26,10 +26,13 @@ import { useTasksFunctions } from "../hooks/tasks_hooks"; //Состояние //Стили const STYLES = { MENU_ITEM_DELIMITER: { borderBottom: "1px solid lightgrey" }, - CARD: (indicatorClr, bgClr) => { - const i = indicatorClr ? { borderLeft: `solid ${indicatorClr}` } : null; - const bc = bgClr ? { backgroundColor: bgClr } : null; - return { ...i, ...bc }; + CARD: (task, colorRule) => { + const expiredColor = getTaskExpiredColor(task); + const backgroundColor = task.nClosed ? "#d3d3d3" : colorRule.SCOLOR ? getTaskBgColorByRule(task, colorRule) : null; + return { + ...(expiredColor ? { borderLeft: `solid ${expiredColor}` } : {}), + ...(backgroundColor ? { backgroundColor: backgroundColor } : {}) + }; }, CARD_HEADER_TITLE: { padding: "4px", @@ -42,14 +45,12 @@ const STYLES = { }, CARD_HEADER: { padding: 0, cursor: "pointer" }, CARD_CONTENT: { padding: "4px !important" }, - CARD_CONTENT_BOX: { display: "flex", alignItems: "center" }, - STACK_SENDER: { alignItems: "center", marginLeft: "auto" }, - TYPOGRAPHY_SECONDARY: { - color: "text.secondary", - fontSize: 14 - }, + CARD_CONTENT_BOX: { display: "flex", alignItems: "center", width: "100%" }, + STACK_SENDER: { alignItems: "center", marginLeft: "auto", width: "50%", justifyContent: "flex-end", paddingLeft: "10px", gap: "5px" }, + TYPOGRAPHY_TASK: { color: "text.secondary", fontSize: 14, width: "40%", overflow: "hidden" }, + TYPOGRAPHY_SENDER: { color: "text.secondary", fontSize: 14, width: "80%", overflow: "hidden", textAlign: "end" }, ICON_COLOR: linked => { - return { color: theme => (linked ? TASK_COLORS.LINKED : theme.palette.grey[500]) }; + return { color: theme => (linked ? TASK_COLORS.LINKED : theme.palette.grey[500]), width: "10%" }; } }; @@ -60,6 +61,7 @@ const STYLES = { //Действия карточки события const CardActions = ({ taskRn, + taskClosed, menuItems, cardActions, onMethodsMenuButtonClick, @@ -92,6 +94,7 @@ const CardActions = ({ sx={action.delimiter ? STYLES.MENU_ITEM_DELIMITER : {}} key={`${taskRn}_${action.method}`} onClick={() => handleActionClick(action)} + disabled={taskClosed === 1 && action.disableClosed ? true : false} > {action.icon} {action.name} @@ -106,6 +109,7 @@ const CardActions = ({ //Контроль свойств - Действия карточки события CardActions.propTypes = { taskRn: PropTypes.number.isRequired, + taskClosed: PropTypes.oneOf([0, 1]).isRequired, menuItems: PropTypes.array.isRequired, cardActions: PropTypes.object.isRequired, onMethodsMenuButtonClick: PropTypes.func.isRequired, @@ -330,12 +334,7 @@ const TaskCard = ({ task, index, onTasksReload, colorRule, pointSettings, onOpen ) : null} {provided => ( - + {task.sDescription} @@ -355,6 +355,7 @@ const TaskCard = ({ task, index, onTasksReload, colorRule, pointSettings, onOpen action={ assignment - {task.name} + + {task.name} + {task.sSender ? ( - {task.sSender} + + {task.sSender} + ) : null} diff --git a/app/panels/clnt_task_board/components/task_form.js b/app/panels/clnt_task_board/components/task_form.js index 12d5882..1cfaf21 100644 --- a/app/panels/clnt_task_board/components/task_form.js +++ b/app/panels/clnt_task_board/components/task_form.js @@ -7,14 +7,12 @@ //Подключение библиотек //--------------------- -import React, { useState, useEffect, useCallback } from "react"; //Классы React +import React, { useState, useCallback } from "react"; //Классы React import PropTypes from "prop-types"; //Контроль свойств компонента import { Box, Typography, Tabs, Tab, InputAdornment, IconButton, Icon } from "@mui/material"; //Интерфейсные компоненты import { TaskFormTabInfo } from "./task_form_tab_info"; //Вкладка основной информации import { TaskFormTabExecutor } from "./task_form_tab_executor"; //Вкладка информации об исполнителе import { TaskFormTabProps } from "./task_form_tab_props"; //Вкладка информации со свойствами -import { useDocsProps } from "../hooks/task_dialog_hooks"; //Хук для получения свойств раздела "События" -import { hasValue } from "../../../core/utils"; //--------- //Константы @@ -74,13 +72,10 @@ export const getInputProps = (onClick, disabled = false, icon = "list") => { //----------- //Форма события -const TaskForm = ({ task, taskType, onTaskChange, editable, onEventNextNumbGet, onDPReady }) => { +const TaskForm = ({ task, taskType, editable, docProps, onTaskChange, onEventNextNumbGet }) => { //Состояние вкладки const [tab, setTab] = useState(0); - //Состояние допустимых дополнительных свойств - const [docProps] = useDocsProps(taskType); - //При изменении вкладки const handleTabChange = (e, newValue) => { setTab(newValue); @@ -107,24 +102,16 @@ const TaskForm = ({ task, taskType, onTaskChange, editable, onEventNextNumbGet, [onTaskChange, task.docProps] ); - //Проверка заполненности всех обязательных доп. свойств - useEffect(() => { - //Считываем количество незаполненных обязательных свойств - let notFilled = docProps.props.filter(docProp => docProp.BREQUIRE === true && !hasValue(task.docProps[docProp.SFORMATTED_ID])).length; - //Если доп. свойства загрузились и количество незаполненных = 0 - доп. свойства готовы, иначе не готовы - docProps.loaded && notFilled === 0 ? onDPReady(true) : onDPReady(false); - }, [docProps, onDPReady, task.docProps]); - //Генерация содержимого return ( - {task.nRn ? "Исправление события" : "Добавление события"} + {task.nRn ? `Исправление события${task.nClosed ? " (событые аннулировано)" : ""}` : "Добавление события"} - {docProps.props.length > 0 ? : null} + {docProps.length > 0 ? : null} @@ -132,7 +119,7 @@ const TaskForm = ({ task, taskType, onTaskChange, editable, onEventNextNumbGet, - {docProps.props.length > 0 ? ( + {docProps.length > 0 ? ( @@ -145,10 +132,10 @@ const TaskForm = ({ task, taskType, onTaskChange, editable, onEventNextNumbGet, TaskForm.propTypes = { task: PropTypes.object.isRequired, taskType: PropTypes.string.isRequired, - onTaskChange: PropTypes.func.isRequired, editable: PropTypes.bool.isRequired, - onEventNextNumbGet: PropTypes.func.isRequired, - onDPReady: PropTypes.func.isRequired + docProps: PropTypes.array, + onTaskChange: PropTypes.func.isRequired, + onEventNextNumbGet: PropTypes.func.isRequired }; //---------------- diff --git a/app/panels/clnt_task_board/components/task_form_tab_info.js b/app/panels/clnt_task_board/components/task_form_tab_info.js index b97f7c8..9dcfa6a 100644 --- a/app/panels/clnt_task_board/components/task_form_tab_info.js +++ b/app/panels/clnt_task_board/components/task_form_tab_info.js @@ -89,7 +89,7 @@ const TaskFormTabInfo = ({ task, editable, onFieldEdit, onEventNextNumbGet }) => value={task.sCrn} variant="standard" onChange={onFieldEdit} - InputProps={getInputProps(handleCrnChange)} + InputProps={getInputProps(handleCrnChange, task.isUpdate || task.nClosed === 1)} required disabled={task.isUpdate} /> @@ -159,8 +159,8 @@ const TaskFormTabInfo = ({ task, editable, onFieldEdit, onEventNextNumbGet }) => value={task.sClntClients} variant="standard" onChange={onFieldEdit} - disabled={!task.sType} - InputProps={getInputProps(() => handleClntClientsChange(), !task.sType)} + disabled={!task.sType || task.nClosed === 1} + InputProps={getInputProps(() => handleClntClientsChange(), !task.sType || task.nClosed === 1)} > value={task.sClntClnperson} variant="standard" onChange={onFieldEdit} - disabled={!task.sType} - InputProps={getInputProps(() => handleClntClnpersonChange(), !task.sType)} + disabled={!task.sType || task.nClosed === 1} + InputProps={getInputProps(() => handleClntClnpersonChange(), !task.sType || task.nClosed === 1)} > diff --git a/app/panels/clnt_task_board/components/task_form_tab_props.js b/app/panels/clnt_task_board/components/task_form_tab_props.js index dc89940..acfccb2 100644 --- a/app/panels/clnt_task_board/components/task_form_tab_props.js +++ b/app/panels/clnt_task_board/components/task_form_tab_props.js @@ -101,7 +101,7 @@ const TaskFormTabProps = ({ task, docProps, onPropEdit }) => { return ( - {docProps.props.map((docProp, index) => { + {docProps.map((docProp, index) => { return docProp.BSHOW_IN_GRID ? ( { //Контроль свойств - Вкладка информации со свойствами TaskFormTabProps.propTypes = { task: PropTypes.object.isRequired, - docProps: PropTypes.object.isRequired, + docProps: PropTypes.array.isRequired, onPropEdit: PropTypes.func.isRequired }; diff --git a/app/panels/clnt_task_board/hooks/task_dialog_hooks.js b/app/panels/clnt_task_board/hooks/task_dialog_hooks.js index 414c369..3433fc7 100644 --- a/app/panels/clnt_task_board/hooks/task_dialog_hooks.js +++ b/app/panels/clnt_task_board/hooks/task_dialog_hooks.js @@ -74,6 +74,7 @@ const useClientEvent = (taskRn, taskType = "") => { setTask(pv => ({ ...pv, sCrn: data.XEVENT.SCRN, + nClosed: data.XEVENT.NCLOSED, sPrefix: data.XEVENT.SPREF, sNumber: data.XEVENT.SNUMB, sType: data.XEVENT.STYPE, diff --git a/app/panels/clnt_task_board/hooks/tasks_hooks.js b/app/panels/clnt_task_board/hooks/tasks_hooks.js index a6437e9..7175217 100644 --- a/app/panels/clnt_task_board/hooks/tasks_hooks.js +++ b/app/panels/clnt_task_board/hooks/tasks_hooks.js @@ -326,6 +326,7 @@ const useTasks = (filterValues, ordersValues) => { nRn: task.NRN, sCrn: "", nCrn: task.NCRN, + nClosed: task.NCLOSED, sPrefix: task.SEVPREF, sNumber: task.SEVNUMB, sType: task.SEVTYPE_CODE, diff --git a/app/panels/clnt_task_board/layouts.js b/app/panels/clnt_task_board/layouts.js index 474ef56..3187dcc 100644 --- a/app/panels/clnt_task_board/layouts.js +++ b/app/panels/clnt_task_board/layouts.js @@ -208,6 +208,7 @@ export const makeCardActionsArray = (onEdit, onEditClient, onDelete, onStateChan delimiter: false, tasksReload: false, needAccountsReload: false, + disableClosed: false, func: onEdit }, { @@ -218,6 +219,7 @@ export const makeCardActionsArray = (onEdit, onEditClient, onDelete, onStateChan delimiter: false, tasksReload: false, needAccountsReload: false, + disableClosed: false, func: onEditClient }, { @@ -228,6 +230,7 @@ export const makeCardActionsArray = (onEdit, onEditClient, onDelete, onStateChan delimiter: false, tasksReload: true, needAccountsReload: false, + disableClosed: false, func: onMove }, { @@ -238,6 +241,7 @@ export const makeCardActionsArray = (onEdit, onEditClient, onDelete, onStateChan delimiter: true, tasksReload: true, needAccountsReload: false, + disableClosed: false, func: onDelete }, { @@ -248,6 +252,7 @@ export const makeCardActionsArray = (onEdit, onEditClient, onDelete, onStateChan delimiter: false, tasksReload: true, needAccountsReload: true, + disableClosed: true, func: onStateChange }, { @@ -258,6 +263,7 @@ export const makeCardActionsArray = (onEdit, onEditClient, onDelete, onStateChan delimiter: false, tasksReload: true, needAccountsReload: true, + disableClosed: true, func: onReturn }, { @@ -268,6 +274,7 @@ export const makeCardActionsArray = (onEdit, onEditClient, onDelete, onStateChan delimiter: true, tasksReload: true, needAccountsReload: true, + disableClosed: true, func: onSend }, { @@ -278,6 +285,7 @@ export const makeCardActionsArray = (onEdit, onEditClient, onDelete, onStateChan delimiter: true, tasksReload: false, needAccountsReload: false, + disableClosed: false, func: onNotesOpen }, { @@ -288,6 +296,7 @@ export const makeCardActionsArray = (onEdit, onEditClient, onDelete, onStateChan delimiter: false, tasksReload: false, needAccountsReload: false, + disableClosed: false, func: onFileLinksOpen } ]; diff --git a/app/panels/clnt_task_board/task_dialog.js b/app/panels/clnt_task_board/task_dialog.js index d616134..549aac8 100644 --- a/app/panels/clnt_task_board/task_dialog.js +++ b/app/panels/clnt_task_board/task_dialog.js @@ -7,14 +7,16 @@ //Подключение библиотек //--------------------- -import React, { useState, useCallback, useContext } from "react"; //Классы React +import React, { useState, useCallback, useContext, useEffect } from "react"; //Классы React import PropTypes from "prop-types"; //Контроль свойств компонента import { Dialog, DialogContent, DialogActions, Button } from "@mui/material"; //Интерфейсные компоненты import { useClientEvent } from "./hooks/task_dialog_hooks"; //Хук для события +import { useDocsProps } from "./hooks/task_dialog_hooks"; //Хук для получения доп. свойств раздела "События" import { TaskForm } from "./components/task_form"; //Форма события import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером import { object2Base64XML } from "../../core/utils"; //Вспомогательные функции import { COMMON_STYLES } from "./styles"; //Общие стили +import { hasValue } from "../../core/utils"; //Вспомогательные процедуры и функции //--------- //Константы @@ -39,15 +41,15 @@ const TaskDialog = ({ taskRn, taskType, editable, onTasksReload, onClose }) => { //Собственное состояние const [task, setTask] = useClientEvent(taskRn, taskType); - //Состояние заполненности всех обязательных свойств - const [dpReady, setDPReady] = useState(false); + //Состояние допустимых дополнительных свойств + const [docProps] = useDocsProps(taskType); + + //Состояние заполненности всех обязательных доп. свойств + const [docPropsReady, setDocPropsReady] = useState(false); //Подключение к контексту взаимодействия с сервером const { executeStored, SERV_DATA_TYPE_CLOB } = useContext(BackEndСtx); - //При изменении заполненности всех обязательных свойств - const handleDPReady = useCallback(v => setDPReady(v), []); - //При изменении информации о задаче const handleTaskChange = useCallback( newTaskValues => { @@ -129,37 +131,58 @@ const TaskDialog = ({ taskRn, taskType, editable, onTasksReload, onClose }) => { } }, [executeStored, setTask, task.sPrefix]); + //Проверка заполненности всех обязательных доп. свойств + useEffect(() => { + //Если доп. свойства загрузились + if (docProps.loaded) { + //Проверяем остались ли обязательные незаполненные свойства + let notFilled = docProps.props.some(docProp => docProp.BREQUIRE === true && !hasValue(task.docProps[docProp.SFORMATTED_ID])); + //Если незаполненных обязательных доп. свойств не осталось - доп. свойства готовы, иначе не готовы + setDocPropsReady(!notFilled); + } else { + //Доп. свойства не готовы + setDocPropsReady(false); + } + }, [docProps.loaded, docProps.props, task.docProps]); + //Генерация содержимого return ( - - - - - {onClose ? ( - - {taskRn ? ( - - ) : ( - - )} - - - ) : null} - + <> + {!task.init && docProps.loaded && ( + + + + + {onClose ? ( + + {taskRn ? ( + + ) : ( + + )} + + + ) : null} + + )}{" "} + ); }; diff --git a/db/PKG_P8PANELS_CLNTTSKBRD.pck b/db/PKG_P8PANELS_CLNTTSKBRD.pck index 979b611..be12480 100644 --- a/db/PKG_P8PANELS_CLNTTSKBRD.pck +++ b/db/PKG_P8PANELS_CLNTTSKBRD.pck @@ -1396,6 +1396,7 @@ create or replace package body PKG_P8PANELS_CLNTTSKBRD as PKG_XFAST.DOWN_NODE(SNAME => 'XDATA'); PKG_XFAST.DOWN_NODE(SNAME => 'XEVENT'); PKG_XFAST.ATTR(SNAME => 'SCRN', SVALUE => SCRN); + PKG_XFAST.ATTR(SNAME => 'NCLOSED', NVALUE => RCLNEVENTS.CLOSED); PKG_XFAST.ATTR(SNAME => 'SPREF', SVALUE => RCLNEVENTS.EVENT_PREF); PKG_XFAST.ATTR(SNAME => 'SNUMB', SVALUE => RCLNEVENTS.EVENT_NUMB); PKG_XFAST.ATTR(SNAME => 'STYPE', SVALUE => STYPE);