From a81dbae85e8b594146a1f185e24c22649a3f6a3b Mon Sep 17 00:00:00 2001 From: Macbook Date: Tue, 9 Dec 2025 09:16:01 +0300 Subject: [PATCH] =?UTF-8?q?=D1=80=D0=B5=D0=B4=D0=B0=D0=BA=D1=82=D0=B8?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D1=8F=D1=89=D0=B8?= =?UTF-8?q?=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__pycache__/toolbox.cpython-313.pyc | Bin 2360 -> 3232 bytes api/routers/toolbox.py | 14 ++- api/static/js/index.js | 84 +++++++++++++++--- db/__init__.py | 32 +++++-- db/__pycache__/__init__.cpython-313.pyc | Bin 8362 -> 8624 bytes .../__pycache__/toolbox.cpython-313.pyc | Bin 8701 -> 8701 bytes db/handlers/toolbox.py | 2 +- .../__pycache__/toolbox.cpython-313.pyc | Bin 2147 -> 2186 bytes db/schemas/toolbox.py | 1 + 9 files changed, 111 insertions(+), 22 deletions(-) diff --git a/api/routers/__pycache__/toolbox.cpython-313.pyc b/api/routers/__pycache__/toolbox.cpython-313.pyc index eb7f3886ab2987c5b0acea054a3d148b648f36d1..be0dbf3e85fc86fe479dff9a089537a3328f7aab 100644 GIT binary patch delta 676 zcmY*XO>7cD7~OAo*j=D(fvs4!P3h7GizbRKlvrw1#6xXDP$a#OG$?3jjF5p%(2K1- z=*^J1crXnIO+2Dp^k5S>7?0bZq>*^>=8?$BgNZXxjeg0#eczim-@Kjddw0XD^c@Zx zM{8?0T3nOr$~cdpKKCh}wcYeF{r^f^()P4;fzR@OE-Oc1xEhA^h{kO|@qZIRmqt%q89AkT;=5UJGT?lf*L;r^J3%+;rEIE8(~u+KUjkqIOiJ++e4h zJLX&Sqq%FoBT3}9iB#IAPk)0vLfd4`60wVaGCU9lz4W(7^K?%J9QvQQ|~zNLcUnN zHS{HN)m&FHDh0e=%wzUFK?@$EFDx@q8L;eK#5M&*>|x3zgOd!{Khu1i7tLUW}VGo6Mh|HL$V+Zc#&DF1}exwHW z)j;Fno|s=gz!1u)!ob1cr!n~%(*?$s$=jI=bnmcmwR<;tPvE%1B6)*bxWWG;Cj+1L z&tf54CW{ghqEC -
+
@@ -525,7 +525,7 @@ function addToolbox() {
@@ -533,8 +533,22 @@ function addToolbox() {
`; + // Если редактирование + if (editData) { + modal.querySelector('#toolboxTitle').value = editData.title; + modal.querySelector('#toolboxDescription').value = editData.description; + modal.querySelector('#toolboxMonitoring').checked = editData.monitoring; + modal.querySelector('#addToolboxModalLabel').textContent = 'Редактировать склад'; + modal.querySelector('#submitToolboxText').textContent = 'Сохранить'; + if (editData.owner_id) { + modal.querySelector('#toolboxMonitoringContainer').classList.add('d-none'); + } + } + + // Добавляем модальное окно в DOM document.body.appendChild(modal); + // Инициализация модального окна const bsModal = new bootstrap.Modal(modal); @@ -623,39 +637,76 @@ function addToolbox() { const userId = userData.id; + let editToolboxData = {} + + if (editData) { + Object.keys(toolboxData).forEach(key => { + if (toolboxData[key] !== editData[key]) { + editToolboxData[key] = toolboxData[key]; + } + }); + } + + if (Object.keys(editToolboxData).length === 0 && editData) { + showInfo('Новые данные склада совпадают с текущими', 'warning'); + // Возвращаем кнопку в исходное состояние + submitBtn.disabled = false; + spinner.style.display = 'none'; + return; + } + try { - // Отправка данных (замените на ваш реальный endpoint) - const response = await apiRequest("/toolbox/", { toolboxData, userId }); + // Отправка данных + + let method = 'POST' + let sendData = { toolboxData, userId } + + if (editData) { + method = 'PUT'; + const toolboxId = editData.id; + sendData = { toolboxId, userId, editToolboxData }; + } + + const response = await apiRequest("/toolbox/", sendData, method); if (response.status !== 'ok') { - throw new Error('Ошибка при добавлении склада'); + if (!editData) { + throw new Error('Ошибка при добавлении склада'); + } else { + throw new Error('Ошибка при обновлении склада'); + } } // Успешная отправка bsModal.hide(); // Показываем уведомление об успехе - showInfo('Склад успешно добавлен', 'success'); + const successMessageText = editData ? 'Склад успешно обновлен' : 'Склад успешно добавлен'; + showInfo(successMessageText, 'success'); // Здесь можно добавить обновление списка складов await uploadTab('toolbox'); } catch (error) { - console.error('Ошибка при добавлении склада:', error); + console.error('Ошибка при добавлении (обновлении) склада:', error); // Возвращаем кнопку в исходное состояние submitBtn.disabled = false; spinner.style.display = 'none'; // Показываем сообщение об ошибке - showInfo('Ошибка при добавлении склада. Попробуйте еще раз.', 'error'); + const errorMessageText = editData ? 'Ошибка при обновлении склада' : 'Ошибка при добавлении склада'; + showInfo(errorMessageText, 'error'); // Можно добавить более детальное сообщение об ошибке const errorDiv = document.createElement('div'); errorDiv.className = 'alert alert-danger mt-3'; - errorDiv.innerHTML = ` + errorDiv.innerHTML = !editData ? ` Ошибка! Не удалось добавить склад. Проверьте соединение и попробуйте еще раз. + ` : ` + Ошибка! Не удалось обновить склад. + Проверьте соединение и попробуйте еще раз. `; const modalBody = modal.querySelector('.modal-body'); @@ -855,6 +906,9 @@ async function loadToolboxContent(toolboxId) {
${toolboxInfo?.title || 'Склад'}

${toolboxInfo?.description || 'Описание отсутствует'}

+ ${toolboxOwn} @@ -910,6 +964,14 @@ async function loadToolboxContent(toolboxId) { `; + if (accessData.manage_toolboxes) { + contentContainer.querySelector('#editToolbox').addEventListener('click', () => { + addToolbox(toolboxInfo); + }); + } else { + contentContainer.querySelector('#editToolbox').remove(); + } + // Инициализация таблицы с данными await initializeToolboxTable(processedData, toolboxOwn, quantityMonitoring); diff --git a/db/__init__.py b/db/__init__.py index 5c2ae57..e5e47c0 100644 --- a/db/__init__.py +++ b/db/__init__.py @@ -1,4 +1,4 @@ -from sqlalchemy import delete, update +from sqlalchemy import delete from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker from sqlalchemy.exc import InvalidRequestError @@ -17,6 +17,7 @@ Base = declarative_base() class CRUD: + @staticmethod async def create(db_data, refresh: bool = False): try: is_lst = isinstance(db_data, list) @@ -43,9 +44,10 @@ class CRUD: logger.debug("Запись создана") return db_data if refresh else None except Exception as e: - logger.error(f"Ошибка создания: {str(e)}", exc_debug=True) + logger.error(f"Ошибка создания: {str(e)}", exc_info=True) return None + @staticmethod async def read(query, all: bool = False): try: async with SessionLocal() as db: @@ -58,9 +60,10 @@ class CRUD: else results.unique().scalars().first() ) except Exception as e: - logger.error(f"Ошибка чтения: {str(e)}", exc_debug=True) + logger.error(f"Ошибка чтения: {str(e)}", exc_info=True) return None + @staticmethod async def delete(db_data) -> bool: def itemdebug(instance): from sqlalchemy import inspect @@ -98,18 +101,29 @@ class CRUD: return True except Exception as e: await db.rollback() - logger.error(f"Ошибка удаления: {str(e)}", exc_debug=True) + logger.error(f"Ошибка удаления: {str(e)}", exc_info=True) return False - async def update(db_data, id, **kwargs): + @staticmethod + async def update(model, id: int, **kwargs): + from sqlalchemy import update as sa_update + async with SessionLocal() as db: try: - query = update(db_data).where(db_data.id == id).values(**kwargs) - item = await db.execute(query) + query = ( + sa_update(model) + .where(model.id == id) + .values(**kwargs) + .execution_options(synchronize_session="fetch") + ) + await db.execute(query) await db.commit() + logger.debug("Запись обновлена") - return await db.get(db_data, id) + + return await db.get(model, id) + except Exception as e: await db.rollback() - logger.error(f"Ошибка обновления: {str(e)}", exc_debug=True) + logger.error(f"Ошибка обновления: {str(e)}", exc_info=True) return None diff --git a/db/__pycache__/__init__.cpython-313.pyc b/db/__pycache__/__init__.cpython-313.pyc index 9a1d819711988b8104d89c0f5160f552e8800fc8..3f58611e1ada1fe2f444fcb99fd0c1a3ef59e80d 100644 GIT binary patch delta 2320 zcmZuyU2Gf25#GIj{z;_C;zrlzMY+!otvGV@9vGs-{g9Bd_FgUvH9-t+SPq4J<%T|DIu>AgBWy{%uq&CC=0W~ zjL1Ys7H6dynaMK>Q=GLltIlXlb7XneHREP(M^sgiPF+Lf53hii1t|oEK@fT zEK&E(dk1^WDO5Lqk5i^FHf7s91-_O7o&5!t>NAN?Mn0DFb2t3o_IwCp4N{4}DTVmizRAqn z8ae$8JWs+ChsQTa&SKv=LnY+`Ax#D1#39ZApAYySh}DmIC6u$+cg`p%_fF75#sot( zH2!dW>5%(0LtbZq$cq=NW$0!3oY}4{fFfuuH7g6O)vW!}dpt7*C;e2EbN+SgtRcmL2F41U8mh7uzsdPE&O+eyS|3rS_o?qwIxTtM7rZF|b`l7- jSU0nbfg{j@ST6x|L`vz$B*BMLOT8^h`#&Ry&c^=%C<+FH delta 2062 zcmZ8iU2IfE6rQ=i``@MA?cVEU7)*E+?rbVS}?M*x$R!dmTil3w?dza zKKNo{x{O!|iS!Xn{7LGAF+K?GgC@p6(G)MJG4X}?(t-q|Mm^_lA?PIY&3De6IWu$4 zxpO~GzP~4M+wb=fXyw1R70#?H2ehG9O2{dq6P@;vG-Wg`Fd>Sv&?lxPCOKT}lhX=Q z(kfFOS?Y78-OTN9xzCgKGOxpxJ|FYJTD8xg4zK{|Tv=cFy@>42`ZCe-TtxI`TFY}` zM}7#27be=vbD@{Fc~~f`w32Kn>(zZb1QyP!AceQX`LMCttkg=jR|LW$8fhiEznO6LqgHWTh@a z7wgHWG)kEa8p+YfYZ^sY99cz~sk*D4FqaNN81ck?^KS`XNglU(d^ndkhbBk(%W50- z@YmJ4dKYYF%VQ=RF>TSv=WS(pVr;BXV%7W;wVhV;>*`S|%s=aTj!LB^-wX5S+~0}S zA-sf_X)rKM7^~xN`kO~LInG`wFssB`P#r~x0mNlnes$7hQw(j`LjbnQOlz`OvRFGv zmJATZ#x~%j#7rY^yOWv0R0q;W(dHX~o8$yp5qKc*nbfu98<_t(Fe}l=dA{Zuzz=Kc z);)!m3V`Dc-0^EQ9dysU8tS2$ZqTzQ5Ox5>C5BPA*+hm7GP z55!4ftvHW0;A~$x2u7%~^ZkqMcH&eyzt;&9?~f?K-C$`cP?W!8pl%5~ANfJn4=e>= z)?_isVJ{WfUZNEE7$U#MDNCpMG&)kp@(y%NvJ+z>t3|l71V`6RKp2H{s`x-t| zug5=dk^V!__d#!f?vIg!7*40D#26%GTmkC{U-j1W_J;5SPBm~E7KMWi{7^$g6m^Lo zZODmB1fM1K2_VO8qsXIB8l=$}4HPpDJ4%G1qFiAJ;??oI+MB z3Cf@o<;XFEjaZdLVRhIN7E7g|Rgk08_lgkL*yUjCMzD6)chYycDe-M^7h3N>vw!aCt4*ED zkL7a95*+G@!gxizaC@<91q}t?#cAAX47B;j4 zU-V0`<>ERo*eo{ERExCOgpL;5WUyb{DB|p9Wv`$vK1x$vzQwIRZA<&KG&C_$WE;VVZAHLGqms>VE@zdDQeik}luE2HG+8pO zT+Z>w;0qy@k2Hu3p&Gh{FU*@{Rces6xzZg1!)mu*)=mS5VWqiUZkh}IMqs!zK)rG! zi#VQeeY}qCgkkLfJQj^keBP#(oAx={;%fbmxfBepzQDikf}`LfkiPi|1(n{mj%9$k0HzUOrQMRZdF{{yzv yV_2qh%l}>9c0D;Zk)JG@304F{c$IH<4u_uiD01^NfV}EVJU_z7E_QCASjXw z7Acb6{DJX1GvkxVFIWv2WhP6qo#5puE=erOOwLU$$;eNc{D94#am8c>_DNz4Y(gKH s7+EbQ6n|y_QlFWD0-u>C?_@7!bepWtp~^4GXwi}Kl>tZNcZSIi*h?8*Cx>yU@=GvUbfkP` K08&LNK;r=+Js@8I diff --git a/db/schemas/toolbox.py b/db/schemas/toolbox.py index 9520d1b..ee5c535 100644 --- a/db/schemas/toolbox.py +++ b/db/schemas/toolbox.py @@ -27,5 +27,6 @@ class Toolbox(Base): async def save(self): return await CRUD.create(self, refresh=True) + @staticmethod async def edit(id: int, **kwargs): return await CRUD.update(Toolbox, id, **kwargs)