diff --git a/README.md b/README.md index 04caeaf93172d3348f20f14339521216b4f0e728..4420359665d82aafccb5643ef792d64a99249c52 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@

logo

-

Dash-FastAPI-Admin v1.0.4

+

Dash-FastAPI-Admin v1.0.5

基于Dash+FastAPI前后端分离的纯Python快速开发框架

- + @@ -130,10 +130,14 @@ python3 app.py ``` ## 交流与赞助 -如果有对本项目及FastAPI感兴趣的朋友,欢迎加入知识星球一起交流学习,让我们一起变得更强。如果你觉得这个项目帮助到了你,你可以请作者喝杯咖啡表示鼓励☕。 +如果有对本项目及FastAPI感兴趣的朋友,欢迎加入知识星球一起交流学习,让我们一起变得更强。如果你觉得这个项目帮助到了你,你可以请作者喝杯咖啡表示鼓励☕。扫描下面微信二维码添加微信备注DF-Admin即可进群,也欢迎大家加入dash大神费弗里的知识星球学习更多dash开发知识。 + + + +
zsxq zanzhu
wxcodedashzsxq
\ No newline at end of file diff --git a/dash-fastapi-backend/module_admin/dao/dept_dao.py b/dash-fastapi-backend/module_admin/dao/dept_dao.py index e08f85922ee4185da1a0ddcd16855452c111df34..dc5098d57a05d03f28288541298b4ca4da44d860 100644 --- a/dash-fastapi-backend/module_admin/dao/dept_dao.py +++ b/dash-fastapi-backend/module_admin/dao/dept_dao.py @@ -197,7 +197,7 @@ class DeptDao: """ db_dept = SysDept(**dept.dict()) db.add(db_dept) - db.refresh(db_dept) # 刷新 + db.flush() return db_dept diff --git a/dash-fastapi-backend/module_admin/service/job_service.py b/dash-fastapi-backend/module_admin/service/job_service.py index 571c18fa861125c770cbbf1a0f04a10904a55049..5f50e8cf61b90363b0e07c38409b7e9a94350073 100644 --- a/dash-fastapi-backend/module_admin/service/job_service.py +++ b/dash-fastapi-backend/module_admin/service/job_service.py @@ -167,7 +167,7 @@ class JobService: data = [JobModel(**vars(row)).dict() for row in job_list] job_group_list = await DictDataService.query_dict_data_list_from_cache_services(request.app.state.redis, dict_type='sys_job_group') - job_group_option = [dict(label=item.dict_label, value=item.dict_value) for item in job_group_list] + job_group_option = [dict(label=item.get('dict_label'), value=item.get('dict_value')) for item in job_group_list] job_group_option_dict = {item.get('value'): item for item in job_group_option} for item in data: diff --git a/dash-fastapi-frontend/app.py b/dash-fastapi-frontend/app.py index dd9d815c9b4872028ca9f1165d584d6a0d3b8966..cf8cd500fd759cbab61a0753e82b7c8ee5fc3c6a 100644 --- a/dash-fastapi-frontend/app.py +++ b/dash-fastapi-frontend/app.py @@ -76,20 +76,27 @@ app.layout = html.Div( @app.callback( - [Output('app-mount', 'children'), - Output('redirect-container', 'children', allow_duplicate=True), - Output('global-message-container', 'children', allow_duplicate=True), - Output('api-check-token', 'data', allow_duplicate=True), - Output('current-key-container', 'data'), - Output('menu-info-store-container', 'data'), - Output('menu-list-store-container', 'data'), - Output('search-panel', 'data')], - Input('url-container', 'pathname'), - [State('url-container', 'trigger'), - State('token-container', 'data')], + output=dict( + app_mount=Output('app-mount', 'children'), + redirect_container=Output('redirect-container', 'children', allow_duplicate=True), + global_message_container=Output('global-message-container', 'children', allow_duplicate=True), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True), + menu_current_key=Output('current-key-container', 'data'), + menu_info=Output('menu-info-store-container', 'data'), + menu_list=Output('menu-list-store-container', 'data'), + search_panel_data=Output('search-panel', 'data') + ), + inputs=dict(pathname=Input('url-container', 'pathname')), + state=dict( + url_trigger=State('url-container', 'trigger'), + session_token=State('token-container', 'data') + ), prevent_initial_call=True ) -def router(pathname, trigger, session_token): +def router(pathname, url_trigger, session_token): + """ + 全局路由回调 + """ # 检查当前会话是否已经登录 token_result = session.get('Authorization') # 若已登录 @@ -115,142 +122,136 @@ def router(pathname, trigger, session_token): current_key = '首页' if pathname == '/user/profile': current_key = '个人资料' - if trigger == 'load': + if url_trigger == 'load': # 根据pathname控制渲染行为 if pathname == '/login' or pathname == '/forget': # 重定向到主页面 - return [ - dash.no_update, - dcc.Location( - pathname='/', - id='router-redirect' - ), - None, - {'timestamp': time.time()}, - {'current_key': current_key}, - {'menu_info': menu_info}, - {'menu_list': menu_list}, - search_panel_data - ] + return dict( + app_mount=dash.no_update, + redirect_container=dcc.Location(pathname='/', id='router-redirect'), + global_message_container=None, + api_check_token_trigger={'timestamp': time.time()}, + menu_current_key={'current_key': current_key}, + menu_info={'menu_info': menu_info}, + menu_list={'menu_list': menu_list}, + search_panel_data=search_panel_data + ) # 否则正常渲染主页面 - return [ - views.layout.render_content(user_menu_info), - None, - fuc.FefferyFancyNotification('进入主页面', type='success', autoClose=2000), - {'timestamp': time.time()}, - {'current_key': current_key}, - {'menu_info': menu_info}, - {'menu_list': menu_list}, - search_panel_data - ] + return dict( + app_mount=views.layout.render_content(user_menu_info), + redirect_container=None, + global_message_container=None, + api_check_token_trigger={'timestamp': time.time()}, + menu_current_key={'current_key': current_key}, + menu_info={'menu_info': menu_info}, + menu_list={'menu_list': menu_list}, + search_panel_data=search_panel_data + ) else: - return [ - dash.no_update, - None, - None, - {'timestamp': time.time()}, - {'current_key': current_key}, - {'menu_info': menu_info}, - {'menu_list': menu_list}, - search_panel_data - ] + return dict( + app_mount=dash.no_update, + redirect_container=None, + global_message_container=None, + api_check_token_trigger={'timestamp': time.time()}, + menu_current_key={'current_key': current_key}, + menu_info={'menu_info': menu_info}, + menu_list={'menu_list': menu_list}, + search_panel_data=search_panel_data + ) else: # 渲染404状态页 - return [ - views.page_404.render_content(), - None, - None, - {'timestamp': time.time()}, - dash.no_update, - dash.no_update, - dash.no_update, - dash.no_update - ] + return dict( + app_mount=views.page_404.render_content(), + redirect_container=None, + global_message_container=None, + api_check_token_trigger={'timestamp': time.time()}, + menu_current_key=dash.no_update, + menu_info=dash.no_update, + menu_list=dash.no_update, + search_panel_data=dash.no_update + ) else: - return [ - dash.no_update, - dash.no_update, - dash.no_update, - {'timestamp': time.time()}, - dash.no_update, - dash.no_update, - dash.no_update, - dash.no_update - ] + return dict( + app_mount=dash.no_update, + redirect_container=dash.no_update, + global_message_container=dash.no_update, + api_check_token_trigger={'timestamp': time.time()}, + menu_current_key=dash.no_update, + menu_info=dash.no_update, + menu_list=dash.no_update, + search_panel_data=dash.no_update + ) except Exception as e: print(e) - return [ - dash.no_update, - None, - fuc.FefferyFancyNotification('接口异常', type='error', autoClose=2000), - {'timestamp': time.time()}, - dash.no_update, - dash.no_update, - dash.no_update, - dash.no_update - ] + return dict( + app_mount=dash.no_update, + redirect_container=None, + global_message_container=fuc.FefferyFancyNotification('接口异常', type='error', autoClose=2000), + api_check_token_trigger={'timestamp': time.time()}, + menu_current_key=dash.no_update, + menu_info=dash.no_update, + menu_list=dash.no_update, + search_panel_data=dash.no_update + ) else: # 若未登录 # 根据pathname控制渲染行为 # 检验pathname合法性 if pathname not in RouterConfig.BASIC_VALID_PATHNAME: # 渲染404状态页 - return [ - views.page_404.render_content(), - None, - None, - {'timestamp': time.time()}, - dash.no_update, - dash.no_update, - dash.no_update, - dash.no_update - ] + return dict( + app_mount=views.page_404.render_content(), + redirect_container=None, + global_message_container=None, + api_check_token_trigger={'timestamp': time.time()}, + menu_current_key=dash.no_update, + menu_info=dash.no_update, + menu_list=dash.no_update, + search_panel_data=dash.no_update + ) if pathname == '/login': - return [ - views.login.render_content(), - None, - None, - {'timestamp': time.time()}, - dash.no_update, - dash.no_update, - dash.no_update, - dash.no_update - ] + return dict( + app_mount=views.login.render_content(), + redirect_container=None, + global_message_container=None, + api_check_token_trigger={'timestamp': time.time()}, + menu_current_key=dash.no_update, + menu_info=dash.no_update, + menu_list=dash.no_update, + search_panel_data=dash.no_update + ) if pathname == '/forget': - return [ - views.forget.render_forget_content(), - None, - None, - {'timestamp': time.time()}, - dash.no_update, - dash.no_update, - dash.no_update, - dash.no_update - ] + return dict( + app_mount=views.forget.render_forget_content(), + redirect_container=None, + global_message_container=None, + api_check_token_trigger={'timestamp': time.time()}, + menu_current_key=dash.no_update, + menu_info=dash.no_update, + menu_list=dash.no_update, + search_panel_data=dash.no_update + ) # 否则重定向到登录页 - return [ - dash.no_update, - dcc.Location( - pathname='/login', - id='router-redirect' - ), - None, - {'timestamp': time.time()}, - dash.no_update, - dash.no_update, - dash.no_update, - dash.no_update - ] + return dict( + app_mount=dash.no_update, + redirect_container=dcc.Location(pathname='/login', id='router-redirect'), + global_message_container=None, + api_check_token_trigger={'timestamp': time.time()}, + menu_current_key=dash.no_update, + menu_info=dash.no_update, + menu_list=dash.no_update, + search_panel_data=dash.no_update + ) if __name__ == '__main__': diff --git a/dash-fastapi-frontend/callbacks/forget_c.py b/dash-fastapi-frontend/callbacks/forget_c.py index 9527ce35be12513999a61fe5d8f45e26913d3d7b..7b12a2bac2794f27515e672612eb52ce949a3d22 100644 --- a/dash-fastapi-frontend/callbacks/forget_c.py +++ b/dash-fastapi-frontend/callbacks/forget_c.py @@ -2,6 +2,7 @@ import dash from dash import dcc import feffery_utils_components as fuc from dash.dependencies import Input, Output, State +from dash.exceptions import PreventUpdate from server import app from api.user import forget_user_pwd_api @@ -9,26 +10,32 @@ from api.message import send_message_api @app.callback( - [Output('forget-username-form-item', 'validateStatus'), - Output('forget-password-form-item', 'validateStatus'), - Output('forget-password-again-form-item', 'validateStatus'), - Output('forget-captcha-form-item', 'validateStatus'), - Output('forget-username-form-item', 'help'), - Output('forget-password-form-item', 'help'), - Output('forget-password-again-form-item', 'help'), - Output('forget-captcha-form-item', 'help'), - Output('forget-submit', 'loading'), - Output('redirect-container', 'children', allow_duplicate=True), - Output('global-message-container', 'children', allow_duplicate=True)], - Input('forget-submit', 'nClicks'), - [State('forget-username', 'value'), - State('forget-password', 'value'), - State('forget-password-again', 'value'), - State('forget-input-captcha', 'value'), - State('sms_code-session_id-container', 'data')], + output=dict( + username_form_status=Output('forget-username-form-item', 'validateStatus'), + password_form_status=Output('forget-password-form-item', 'validateStatus'), + password_again_form_status=Output('forget-password-again-form-item', 'validateStatus'), + captcha_form_status=Output('forget-captcha-form-item', 'validateStatus'), + username_form_help=Output('forget-username-form-item', 'help'), + password_form_help=Output('forget-password-form-item', 'help'), + password_again_form_help=Output('forget-password-again-form-item', 'help'), + captcha_form_help=Output('forget-captcha-form-item', 'help'), + submit_loading=Output('forget-submit', 'loading'), + redirect_container=Output('redirect-container', 'children', allow_duplicate=True), + global_message_container=Output('global-message-container', 'children', allow_duplicate=True) + ), + inputs=dict( + nClicks=Input('forget-submit', 'nClicks') + ), + state=dict( + username=State('forget-username', 'value'), + password=State('forget-password', 'value'), + password_again=State('forget-password-again', 'value'), + input_captcha=State('forget-input-captcha', 'value'), + session_id=State('sms_code-session_id-container', 'data') + ), prevent_initial_call=True ) -def login_auth(nClicks, username, password, password_again, input_captcha, session_id): +def forget_auth(nClicks, username, password, password_again, input_captcha, session_id): if nClicks: # 校验全部输入值是否不为空 if all([username, password, password_again, input_captcha]): @@ -39,84 +46,81 @@ def login_auth(nClicks, username, password, password_again, input_captcha, sessi change_result = forget_user_pwd_api(forget_params) if change_result.get('code') == 200: - return [ - None, - None, - None, - None, - None, - None, - None, - None, - True, - dcc.Location( - pathname='/login', - id='forget-redirect' - ), - fuc.FefferyFancyMessage(change_result.get('message'), type='success') - ] + return dict( + username_form_status=None, + password_form_status=None, + password_again_form_status=None, + captcha_form_status=None, + username_form_help=None, + password_form_help=None, + password_again_form_help=None, + captcha_form_help=None, + submit_loading=False, + redirect_container=dcc.Location(pathname='/login', id='forget-redirect'), + global_message_container=fuc.FefferyFancyMessage(change_result.get('message'), type='success') + ) else: - return [ - None, - None, - None, - None, - None, - None, - None, - None, - False, - None, - fuc.FefferyFancyMessage(change_result.get('message'), type='error') - ] + return dict( + username_form_status=None, + password_form_status=None, + password_again_form_status=None, + captcha_form_status=None, + username_form_help=None, + password_form_help=None, + password_again_form_help=None, + captcha_form_help=None, + submit_loading=False, + redirect_container=None, + global_message_container=fuc.FefferyFancyMessage(change_result.get('message'), type='error') + ) except Exception as e: - return [ - None, - None, - None, - None, - None, - None, - None, - None, - False, - None, - fuc.FefferyFancyMessage(str(e), type='error') - ] + return dict( + username_form_status=None, + password_form_status=None, + password_again_form_status=None, + captcha_form_status=None, + username_form_help=None, + password_form_help=None, + password_again_form_help=None, + captcha_form_help=None, + submit_loading=False, + redirect_container=None, + global_message_container=fuc.FefferyFancyMessage(str(e), type='error') + ) else: - return [ - None, - 'error', - 'error', - None, - None, - '两次密码不一致', - '两次密码不一致', - None, - False, - None, - None - ] - - return [ - None if username else 'error', - None if password else 'error', - None if password_again else 'error', - None if input_captcha else 'error', - None if username else '请输入用户名!', - None if password else '请输入新密码!', - None if password_again else '请再次输入新密码!', - None if input_captcha else '请输入短信验证码!', - False, - None, - None - ] - - return [dash.no_update] * 11 + return dict( + username_form_status=None, + password_form_status='error', + password_again_form_status='error', + captcha_form_status=None, + username_form_help=None, + password_form_help='两次密码不一致', + password_again_form_help='两次密码不一致', + captcha_form_help=None, + submit_loading=False, + redirect_container=None, + global_message_container=None + ) + + return dict( + username_form_status=None if username else 'error', + password_form_status=None if password else 'error', + password_again_form_status=None if password_again else 'error', + captcha_form_status=None if input_captcha else 'error', + username_form_help=None if username else '请输入用户名!', + password_form_help=None if password else '请输入新密码!', + password_again_form_help=None if password_again else '请再次输入新密码!', + captcha_form_help=None if input_captcha else '请输入短信验证码!', + submit_loading=False, + redirect_container=None, + global_message_container=None + ) + + raise PreventUpdate @app.callback( diff --git a/dash-fastapi-frontend/callbacks/layout_c/fold_side_menu.py b/dash-fastapi-frontend/callbacks/layout_c/fold_side_menu.py index eed62bb0cf6da518285cd48260812ba8a365ca87..5096ca74a70aeeb16318bc93d035def67215acf1 100644 --- a/dash-fastapi-frontend/callbacks/layout_c/fold_side_menu.py +++ b/dash-fastapi-frontend/callbacks/layout_c/fold_side_menu.py @@ -3,6 +3,7 @@ from dash.dependencies import Input, Output, State from server import app +# 侧边栏折叠回调 app.clientside_callback( ''' (nClicks, collapsed) => { diff --git a/dash-fastapi-frontend/callbacks/login_c.py b/dash-fastapi-frontend/callbacks/login_c.py index 465e1cfcc0206b24c0502b1c6358dcf3228b8245..d423bd013541e7b9a8c9f89fdefd9a2723265e7e 100644 --- a/dash-fastapi-frontend/callbacks/login_c.py +++ b/dash-fastapi-frontend/callbacks/login_c.py @@ -10,24 +10,30 @@ from api.login import login_api, get_captcha_image_api @app.callback( - [Output('login-username-form-item', 'validateStatus'), - Output('login-password-form-item', 'validateStatus'), - Output('login-captcha-form-item', 'validateStatus'), - Output('login-username-form-item', 'help'), - Output('login-password-form-item', 'help'), - Output('login-captcha-form-item', 'help'), - Output('login-captcha-image-container', 'n_clicks'), - Output('login-submit', 'loading'), - Output('token-container', 'data'), - Output('redirect-container', 'children', allow_duplicate=True), - Output('global-message-container', 'children', allow_duplicate=True)], - Input('login-submit', 'nClicks'), - [State('login-username', 'value'), - State('login-password', 'value'), - State('login-captcha', 'value'), - State('captcha_image-session_id-container', 'data'), - State('login-captcha-image-container', 'n_clicks'), - State('captcha-row-container', 'hidden')], + output=dict( + username_form_status=Output('login-username-form-item', 'validateStatus'), + password_form_status=Output('login-password-form-item', 'validateStatus'), + captcha_form_status=Output('login-captcha-form-item', 'validateStatus'), + username_form_help=Output('login-username-form-item', 'help'), + password_form_help=Output('login-password-form-item', 'help'), + captcha_form_help=Output('login-captcha-form-item', 'help'), + image_click=Output('login-captcha-image-container', 'n_clicks'), + submit_loading=Output('login-submit', 'loading'), + token=Output('token-container', 'data'), + redirect_container=Output('redirect-container', 'children', allow_duplicate=True), + global_message_container=Output('global-message-container', 'children', allow_duplicate=True) + ), + inputs=dict( + nClicks=Input('login-submit', 'nClicks') + ), + state=dict( + username=State('login-username', 'value'), + password=State('login-password', 'value'), + input_captcha=State('login-captcha', 'value'), + session_id=State('captcha_image-session_id-container', 'data'), + image_click=State('login-captcha-image-container', 'n_clicks'), + captcha_hidden=State('captcha-row-container', 'hidden') + ), prevent_initial_call=True ) def login_auth(nClicks, username, password, input_captcha, session_id, image_click, captcha_hidden): @@ -43,70 +49,78 @@ def login_auth(nClicks, username, password, input_captcha, session_id, image_cli if userinfo_result['code'] == 200: token = userinfo_result['data']['access_token'] session['Authorization'] = token - - return [ - None, - None, - None, - None, - None, - None, - dash.no_update, - False, - token, - dcc.Location( - pathname='/', - id='login-redirect' - ), - fuc.FefferyFancyMessage('登录成功', type='success'), - ] + return dict( + username_form_status=None, + password_form_status=None, + captcha_form_status=None, + username_form_help=None, + password_form_help=None, + captcha_form_help=None, + image_click=dash.no_update, + submit_loading=False, + token=token, + redirect_container=dcc.Location(pathname='/', id='login-redirect'), + global_message_container=fuc.FefferyFancyMessage('登录成功', type='success') + ) else: - return [ - None, - None, - None, - None, - None, - None, - image_click + 1, - False, - None, - None, - fuc.FefferyFancyMessage(userinfo_result.get('message'), type='error'), - ] + return dict( + username_form_status=None, + password_form_status=None, + captcha_form_status=None, + username_form_help=None, + password_form_help=None, + captcha_form_help=None, + image_click=image_click + 1, + submit_loading=False, + token=None, + redirect_container=None, + global_message_container=fuc.FefferyFancyMessage(userinfo_result.get('message'), type='error') + ) except Exception as e: print(e) - return [ - None, - None, - None, - None, - None, - None, - image_click + 1, - False, - None, - None, - fuc.FefferyFancyMessage('接口异常', type='error'), - ] - - return [ - None if username else 'error', - None if password else 'error', - None if input_captcha else 'error', - None if username else '请输入用户名!', - None if password else '请输入密码!', - None if input_captcha else '请输入验证码!', - dash.no_update, - False, - None, - None, - None - ] - - return [dash.no_update] * 6 + [image_click + 1] + [dash.no_update] * 4 + return dict( + username_form_status=None, + password_form_status=None, + captcha_form_status=None, + username_form_help=None, + password_form_help=None, + captcha_form_help=None, + image_click=image_click + 1, + submit_loading=False, + token=None, + redirect_container=None, + global_message_container=fuc.FefferyFancyMessage('接口异常', type='error') + ) + + return dict( + username_form_status=None if username else 'error', + password_form_status=None if password else 'error', + captcha_form_status=None if input_captcha else 'error', + username_form_help=None if username else '请输入用户名!', + password_form_help=None if password else '请输入密码!', + captcha_form_help=None if input_captcha else '请输入验证码!', + image_click=dash.no_update, + submit_loading=False, + token=None, + redirect_container=None, + global_message_container=None + ) + + return dict( + username_form_status=dash.no_update, + password_form_status=dash.no_update, + captcha_form_status=dash.no_update, + username_form_help=dash.no_update, + password_form_help=dash.no_update, + captcha_form_help=dash.no_update, + image_click=image_click + 1, + submit_loading=dash.no_update, + token=dash.no_update, + redirect_container=dash.no_update, + global_message_container=dash.no_update + ) @app.callback( diff --git a/dash-fastapi-frontend/callbacks/monitor_c/cache_c/control_c.py b/dash-fastapi-frontend/callbacks/monitor_c/cache_c/control_c.py index 16afc774249ff0219976acba4db15d0548f98d1b..d73509237ac95c4d68f3bb7a5aa1e232ec9d2351 100644 --- a/dash-fastapi-frontend/callbacks/monitor_c/cache_c/control_c.py +++ b/dash-fastapi-frontend/callbacks/monitor_c/cache_c/control_c.py @@ -3,6 +3,7 @@ from dash.dependencies import Input, Output, State, ClientsideFunction from server import app +# 初始化echarts图表数据 app.clientside_callback( ''' (n_intervals, data) => { @@ -17,6 +18,7 @@ app.clientside_callback( ) +# 渲染命令统计图表 app.clientside_callback( ClientsideFunction( namespace='clientside_command_stats', @@ -27,6 +29,7 @@ app.clientside_callback( ) +# 渲染内存信息统计图表 app.clientside_callback( ClientsideFunction( namespace='clientside_memory', diff --git a/dash-fastapi-frontend/callbacks/monitor_c/job_c/job_c.py b/dash-fastapi-frontend/callbacks/monitor_c/job_c/job_c.py index 21fbb84aab0b34389e98e65e45c7953802e38a43..d0eb60a8b0b65cfd8b93a78d6756769dc4ffda4d 100644 --- a/dash-fastapi-frontend/callbacks/monitor_c/job_c/job_c.py +++ b/dash-fastapi-frontend/callbacks/monitor_c/job_c/job_c.py @@ -4,6 +4,7 @@ import uuid import json from dash import dcc from dash.dependencies import Input, Output, State, ALL +from dash.exceptions import PreventUpdate import feffery_utils_components as fuc from server import app @@ -12,23 +13,32 @@ from api.dict import query_dict_data_list_api @app.callback( - [Output('job-list-table', 'data', allow_duplicate=True), - Output('job-list-table', 'pagination', allow_duplicate=True), - Output('job-list-table', 'key'), - Output('job-list-table', 'selectedRowKeys'), - Output('api-check-token', 'data', allow_duplicate=True)], - [Input('job-search', 'nClicks'), - Input('job-refresh', 'nClicks'), - Input('job-list-table', 'pagination'), - Input('job-operations-store', 'data')], - [State('job-job_name-input', 'value'), - State('job-job_group-select', 'value'), - State('job-status-select', 'value'), - State('job-button-perms-container', 'data')], + output=dict( + job_table_data=Output('job-list-table', 'data', allow_duplicate=True), + job_table_pagination=Output('job-list-table', 'pagination', allow_duplicate=True), + job_table_key=Output('job-list-table', 'key'), + job_table_selectedrowkeys=Output('job-list-table', 'selectedRowKeys'), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True) + ), + inputs=dict( + search_click=Input('job-search', 'nClicks'), + refresh_click=Input('job-refresh', 'nClicks'), + pagination=Input('job-list-table', 'pagination'), + operations=Input('job-operations-store', 'data') + ), + state=dict( + job_name=State('job-job_name-input', 'value'), + job_group=State('job-job_group-select', 'value'), + status_select=State('job-status-select', 'value'), + button_perms=State('job-button-perms-container', 'data') + ), prevent_initial_call=True ) def get_job_table_data(search_click, refresh_click, pagination, operations, job_name, job_group, status_select, button_perms): + """ + 获取定时任务表格数据回调(进行表格相关增删查改操作后均会触发此回调) + """ query_params = dict( job_name=job_name, job_group=job_group, @@ -101,13 +111,26 @@ def get_job_table_data(search_click, refresh_click, pagination, operations, job_ } if 'monitor:job:query' in button_perms else None ] - return [table_data, table_pagination, str(uuid.uuid4()), None, {'timestamp': time.time()}] + return dict( + job_table_data=table_data, + job_table_pagination=table_pagination, + job_table_key=str(uuid.uuid4()), + job_table_selectedrowkeys=None, + api_check_token_trigger={'timestamp': time.time()} + ) - return [dash.no_update, dash.no_update, dash.no_update, dash.no_update, {'timestamp': time.time()}] + return dict( + job_table_data=dash.no_update, + job_table_pagination=dash.no_update, + job_table_key=dash.no_update, + job_table_selectedrowkeys=dash.no_update, + api_check_token_trigger={'timestamp': time.time()} + ) - return [dash.no_update] * 5 + raise PreventUpdate +# 重置定时任务搜索表单数据回调 app.clientside_callback( ''' (reset_click) => { @@ -126,6 +149,7 @@ app.clientside_callback( ) +# 隐藏/显示定时任务搜索表单回调 app.clientside_callback( ''' (hidden_click, hidden_status) => { @@ -152,6 +176,9 @@ app.clientside_callback( prevent_initial_call=True ) def change_job_edit_button_status(table_rows_selected): + """ + 根据选择的表格数据行数控制编辑按钮状态回调 + """ outputs_list = dash.ctx.outputs_list if outputs_list: if table_rows_selected: @@ -162,7 +189,7 @@ def change_job_edit_button_status(table_rows_selected): return True - return dash.no_update + raise PreventUpdate @app.callback( @@ -171,64 +198,77 @@ def change_job_edit_button_status(table_rows_selected): prevent_initial_call=True ) def change_job_delete_button_status(table_rows_selected): + """ + 根据选择的表格数据行数控制删除按钮状态回调 + """ outputs_list = dash.ctx.outputs_list if outputs_list: if table_rows_selected: - if len(table_rows_selected) > 1: - return False return False return True - return dash.no_update + raise PreventUpdate @app.callback( - [Output('job-modal', 'visible', allow_duplicate=True), - Output('job-modal', 'title'), - Output('job-job_name', 'value'), - Output('job-job_group', 'value'), - Output('job-invoke_target', 'value'), - Output('job-cron_expression', 'value'), - Output('job-job_args', 'value'), - Output('job-job_kwargs', 'value'), - Output('job-misfire_policy', 'value'), - Output('job-concurrent', 'value'), - Output('job-status', 'value'), - Output('api-check-token', 'data', allow_duplicate=True), - Output('job-edit-id-store', 'data'), - Output('job-operations-store-bk', 'data')], - [Input({'type': 'job-operation-button', 'index': ALL}, 'nClicks'), - Input('job-list-table', 'nClicksDropdownItem')], - [State('job-list-table', 'selectedRowKeys'), - State('job-list-table', 'recentlyClickedDropdownItemTitle'), - State('job-list-table', 'recentlyDropdownItemClickedRow')], + output=dict( + modal_visible=Output('job-modal', 'visible', allow_duplicate=True), + modal_title=Output('job-modal', 'title'), + form_value=Output({'type': 'job-form-value', 'index': ALL}, 'value'), + form_label_validate_status=Output({'type': 'job-form-label', 'index': ALL, 'required': True}, 'validateStatus', allow_duplicate=True), + form_label_validate_info=Output({'type': 'job-form-label', 'index': ALL, 'required': True}, 'help', allow_duplicate=True), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True), + edit_row_info=Output('job-edit-id-store', 'data'), + modal_type=Output('job-operations-store-bk', 'data') + ), + inputs=dict( + operation_click=Input({'type': 'job-operation-button', 'index': ALL}, 'nClicks'), + dropdown_click=Input('job-list-table', 'nClicksDropdownItem') + ), + state=dict( + selected_row_keys=State('job-list-table', 'selectedRowKeys'), + recently_clicked_dropdown_item_title=State('job-list-table', 'recentlyClickedDropdownItemTitle'), + recently_dropdown_item_clicked_row=State('job-list-table', 'recentlyDropdownItemClickedRow') + ), prevent_initial_call=True ) def add_edit_job_modal(operation_click, dropdown_click, selected_row_keys, recently_clicked_dropdown_item_title, recently_dropdown_item_clicked_row): + """ + 显示新增或编辑定时任务弹窗回调 + """ trigger_id = dash.ctx.triggered_id if trigger_id == {'index': 'add', 'type': 'job-operation-button'} \ or trigger_id == {'index': 'edit', 'type': 'job-operation-button'} \ or (trigger_id == 'job-list-table' and recently_clicked_dropdown_item_title == '修改'): + # 获取所有输出表单项对应value的index + form_value_list = [x['id']['index'] for x in dash.ctx.outputs_list[2]] + # 获取所有输出表单项对应label的index + form_label_list = [x['id']['index'] for x in dash.ctx.outputs_list[3]] if trigger_id == {'index': 'add', 'type': 'job-operation-button'}: - return [ - True, - '新增任务', - None, - None, - None, - None, - None, - None, - '1', - '1', - '0', - dash.no_update, - None, - {'type': 'add'} - ] + job_info = dict( + job_name=None, + job_group=None, + invoke_target=None, + cron_expression=None, + job_args=None, + job_kwargs=None, + misfire_policy='1', + concurrent='1', + status='0' + ) + return dict( + modal_visible=True, + modal_title='新增任务', + form_value=[job_info.get(k) for k in form_value_list], + form_label_validate_status=[None] * len(form_label_list), + form_label_validate_info=[None] * len(form_label_list), + api_check_token_trigger=dash.no_update, + edit_row_info=None, + modal_type={'type': 'add'} + ) elif trigger_id == {'index': 'edit', 'type': 'job-operation-button'} or (trigger_id == 'job-list-table' and recently_clicked_dropdown_item_title == '修改'): if trigger_id == {'index': 'edit', 'type': 'job-operation-button'}: job_id = int(','.join(selected_row_keys)) @@ -237,125 +277,112 @@ def add_edit_job_modal(operation_click, dropdown_click, selected_row_keys, recen job_info_res = get_job_detail_api(job_id=job_id) if job_info_res['code'] == 200: job_info = job_info_res['data'] - return [ - True, - '编辑任务', - job_info.get('job_name'), - job_info.get('job_group'), - job_info.get('invoke_target'), - job_info.get('cron_expression'), - job_info.get('job_args'), - job_info.get('job_kwargs'), - job_info.get('misfire_policy'), - job_info.get('concurrent'), - job_info.get('status'), - {'timestamp': time.time()}, - job_info if job_info else None, - {'type': 'edit'} - ] - - return [dash.no_update] * 11 + [{'timestamp': time.time()}, None, None] + return dict( + modal_visible=True, + modal_title='编辑任务', + form_value=[job_info.get(k) for k in form_value_list], + form_label_validate_status=[None] * len(form_label_list), + form_label_validate_info=[None] * len(form_label_list), + api_check_token_trigger={'timestamp': time.time()}, + edit_row_info=job_info if job_info else None, + modal_type={'type': 'edit'} + ) + + return dict( + modal_visible=dash.no_update, + modal_title=dash.no_update, + form_value=[dash.no_update] * len(form_value_list), + form_label_validate_status=[dash.no_update] * len(form_label_list), + form_label_validate_info=[dash.no_update] * len(form_label_list), + api_check_token_trigger={'timestamp': time.time()}, + edit_row_info=None, + modal_type=None + ) - return [dash.no_update] * 12 + [None, None] + raise PreventUpdate @app.callback( - [Output('job-job_name-form-item', 'validateStatus'), - Output('job-invoke_target-form-item', 'validateStatus'), - Output('job-cron_expression-form-item', 'validateStatus'), - Output('job-job_name-form-item', 'help'), - Output('job-invoke_target-form-item', 'help'), - Output('job-cron_expression-form-item', 'help'), - Output('job-modal', 'visible'), - Output('job-operations-store', 'data', allow_duplicate=True), - Output('api-check-token', 'data', allow_duplicate=True), - Output('global-message-container', 'children', allow_duplicate=True)], - Input('job-modal', 'okCounts'), - [State('job-operations-store-bk', 'data'), - State('job-edit-id-store', 'data'), - State('job-job_name', 'value'), - State('job-job_group', 'value'), - State('job-invoke_target', 'value'), - State('job-cron_expression', 'value'), - State('job-job_args', 'value'), - State('job-job_kwargs', 'value'), - State('job-misfire_policy', 'value'), - State('job-concurrent', 'value'), - State('job-status', 'value')], + output=dict( + form_label_validate_status=Output({'type': 'job-form-label', 'index': ALL, 'required': True}, 'validateStatus', + allow_duplicate=True), + form_label_validate_info=Output({'type': 'job-form-label', 'index': ALL, 'required': True}, 'help', + allow_duplicate=True), + modal_visible=Output('job-modal', 'visible'), + operations=Output('job-operations-store', 'data', allow_duplicate=True), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True), + global_message_container=Output('global-message-container', 'children', allow_duplicate=True) + ), + inputs=dict( + confirm_trigger=Input('job-modal', 'okCounts') + ), + state=dict( + modal_type=State('job-operations-store-bk', 'data'), + edit_row_info=State('job-edit-id-store', 'data'), + form_value=State({'type': 'job-form-value', 'index': ALL}, 'value'), + form_label=State({'type': 'job-form-label', 'index': ALL, 'required': True}, 'label') + ), prevent_initial_call=True ) -def job_confirm(confirm_trigger, operation_type, cur_job_info, job_name, job_group, invoke_target, cron_expression, - job_args, job_kwargs, misfire_policy, concurrent, status): +def job_confirm(confirm_trigger, modal_type, edit_row_info, form_value, form_label): + """ + 新增或编定时任务弹窗确认回调,实现新增或编辑操作 + """ if confirm_trigger: - if all([job_name, invoke_target, cron_expression]): - params_add = dict(job_name=job_name, job_group=job_group, invoke_target=invoke_target, - cron_expression=cron_expression, job_args=job_args, job_kwargs=job_kwargs, - misfire_policy=misfire_policy, concurrent=concurrent, status=status) - params_edit = dict(job_id=cur_job_info.get('job_id') if cur_job_info else None, job_name=job_name, - job_group=job_group, invoke_target=invoke_target, cron_expression=cron_expression, - job_args=job_args, job_kwargs=job_kwargs, - misfire_policy=misfire_policy, concurrent=concurrent, status=status) + # 获取所有输出表单项对应label的index + form_label_output_list = [x['id']['index'] for x in dash.ctx.outputs_list[0]] + # 获取所有输入表单项对应的value及label + form_value_state = {x['id']['index']: x.get('value') for x in dash.ctx.states_list[-2]} + form_label_state = {x['id']['index']: x.get('value') for x in dash.ctx.states_list[-1]} + if all([form_value_state.get(k) for k in form_label_output_list]): + params_add = form_value_state + params_edit = params_add.copy() + params_edit['job_id'] = edit_row_info.get('job_id') if edit_row_info else None api_res = {} - operation_type = operation_type.get('type') - if operation_type == 'add': + modal_type = modal_type.get('type') + if modal_type == 'add': api_res = add_job_api(params_add) - if operation_type == 'edit': + if modal_type == 'edit': api_res = edit_job_api(params_edit) if api_res.get('code') == 200: - if operation_type == 'add': - return [ - None, - None, - None, - None, - None, - None, - False, - {'type': 'add'}, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('新增成功', type='success') - ] - if operation_type == 'edit': - return [ - None, - None, - None, - None, - None, - None, - False, - {'type': 'edit'}, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('编辑成功', type='success') - ] + if modal_type == 'add': + return dict( + form_label_validate_status=[None] * len(form_label_output_list), + form_label_validate_info=[None] * len(form_label_output_list), + modal_visible=False, + operations={'type': 'add'}, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('新增成功', type='success') + ) + if modal_type == 'edit': + return dict( + form_label_validate_status=[None] * len(form_label_output_list), + form_label_validate_info=[None] * len(form_label_output_list), + modal_visible=False, + operations={'type': 'edit'}, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('编辑成功', type='success') + ) - return [ - None, - None, - None, - None, - None, - None, - dash.no_update, - dash.no_update, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('处理失败', type='error') - ] + return dict( + form_label_validate_status=[None] * len(form_label_output_list), + form_label_validate_info=[None] * len(form_label_output_list), + modal_visible=dash.no_update, + operations=dash.no_update, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('处理失败', type='error') + ) - return [ - None if job_name else 'error', - None if invoke_target else 'error', - None if cron_expression else 'error', - None if job_name else '请输入任务名称!', - None if invoke_target else '请输入调用目标字符串!', - None if cron_expression else '请输入cron执行表达式!', - dash.no_update, - dash.no_update, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('处理失败', type='error') - ] + return dict( + form_label_validate_status=[None if form_value_state.get(k) else 'error' for k in form_label_output_list], + form_label_validate_info=[None if form_value_state.get(k) else f'{form_label_state.get(k)}不能为空!' for k in form_label_output_list], + modal_visible=dash.no_update, + operations=dash.no_update, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('处理失败', type='error') + ) - return [dash.no_update] * 10 + raise PreventUpdate @app.callback( @@ -368,6 +395,9 @@ def job_confirm(confirm_trigger, operation_type, cur_job_info, job_name, job_gro prevent_initial_call=True ) def table_switch_job_status(recently_switch_data_index, recently_switch_status, recently_switch_row): + """ + 表格内切换定时任务状态回调 + """ if recently_switch_data_index: if recently_switch_status: params = dict(job_id=int(recently_switch_row['key']), status='0', type='status') @@ -383,109 +413,89 @@ def table_switch_job_status(recently_switch_data_index, recently_switch_status, ] return [ - dash.no_update, + {'type': 'switch-status'}, {'timestamp': time.time()}, fuc.FefferyFancyMessage('修改失败', type='error') ] - return [dash.no_update] * 3 + raise PreventUpdate @app.callback( - [Output('job_detail-modal', 'visible', allow_duplicate=True), - Output('job_detail-modal', 'title'), - Output('job_detail-job_name-text', 'children'), - Output('job_detail-job_group-text', 'children'), - Output('job_detail-job_executor-text', 'children'), - Output('job_detail-invoke_target-text', 'children'), - Output('job_detail-job_args-text', 'children'), - Output('job_detail-job_kwargs-text', 'children'), - Output('job_detail-cron_expression-text', 'children'), - Output('job_detail-misfire_policy-text', 'children'), - Output('job_detail-concurrent-text', 'children'), - Output('job_detail-status-text', 'children'), - Output('job_detail-create_time-text', 'children'), - Output('api-check-token', 'data', allow_duplicate=True), - Output('global-message-container', 'children', allow_duplicate=True)], - Input('job-list-table', 'nClicksDropdownItem'), - [State('job-list-table', 'recentlyClickedDropdownItemTitle'), - State('job-list-table', 'recentlyDropdownItemClickedRow')], + output=dict( + modal_visible=Output('job_detail-modal', 'visible', allow_duplicate=True), + modal_title=Output('job_detail-modal', 'title'), + form_value=Output({'type': 'job_detail-form-value', 'index': ALL}, 'children'), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True), + global_message_container=Output('global-message-container', 'children', allow_duplicate=True) + ), + inputs=dict( + dropdown_click=Input('job-list-table', 'nClicksDropdownItem') + ), + state=dict( + recently_clicked_dropdown_item_title=State('job-list-table', 'recentlyClickedDropdownItemTitle'), + recently_dropdown_item_clicked_row=State('job-list-table', 'recentlyDropdownItemClickedRow') + ), prevent_initial_call=True ) def get_job_detail_modal(dropdown_click, recently_clicked_dropdown_item_title, recently_dropdown_item_clicked_row): + """ + 显示定时任务详情弹窗回调及执行一次定时任务回调 + """ + # 获取所有输出表单项对应value的index + form_value_list = [x['id']['index'] for x in dash.ctx.outputs_list[-3]] + # 显示定时任务详情弹窗 if dropdown_click and recently_clicked_dropdown_item_title == '任务详细': job_id = int(recently_dropdown_item_clicked_row['key']) job_info_res = get_job_detail_api(job_id=job_id) if job_info_res['code'] == 200: job_info = job_info_res['data'] if job_info.get('misfire_policy') == '1': - misfire_policy = '立即执行' + job_info['misfire_policy'] = '立即执行' elif job_info.get('misfire_policy') == '2': - misfire_policy = '执行一次' + job_info['misfire_policy'] = '执行一次' else: - misfire_policy = '放弃执行' - return [ - True, - '任务详情', - job_info.get('job_name'), - job_info.get('job_group'), - job_info.get('job_executor'), - job_info.get('invoke_target'), - job_info.get('job_args'), - job_info.get('job_kwargs'), - job_info.get('cron_expression'), - misfire_policy, - '是' if job_info.get('concurrent') == '0' else '否', - '正常' if job_info.get('status') == '0' else '停用', - job_info.get('create_time'), - {'timestamp': time.time()}, - None - ] + job_info['misfire_policy'] = '放弃执行' + job_info['concurrent'] = '是' if job_info.get('concurrent') == '0' else '否' + job_info['status'] = '正常' if job_info.get('status') == '0' else '停用' + return dict( + modal_visible=True, + modal_title='任务详情', + form_value=[job_info.get(k) for k in form_value_list], + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=None + ) - return [dash.no_update] * 13 + [{'timestamp': time.time()}, None] + return dict( + modal_visible=dash.no_update, + modal_title=dash.no_update, + form_value=[dash.no_update] * len(form_value_list), + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=None + ) + # 执行一次定时任务 if dropdown_click and recently_clicked_dropdown_item_title == '执行一次': job_id = int(recently_dropdown_item_clicked_row['key']) job_info_res = execute_job_api(dict(job_id=job_id)) if job_info_res['code'] == 200: + return dict( + modal_visible=False, + modal_title=None, + form_value=[None] * len(form_value_list), + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('执行成功', type='success') + ) - return [ - False, - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('执行成功', type='success') - ] - - return [ - False, - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('执行失败', type='success') - ] + return dict( + modal_visible=False, + modal_title=None, + form_value=[None] * len(form_value_list), + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('执行失败', type='error') + ) - return [dash.no_update] * 15 + raise PreventUpdate @app.callback( @@ -501,6 +511,9 @@ def get_job_detail_modal(dropdown_click, recently_clicked_dropdown_item_title, r ) def job_delete_modal(operation_click, dropdown_click, selected_row_keys, recently_clicked_dropdown_item_title, recently_dropdown_item_clicked_row): + """ + 显示删除定时任务二次确认弹窗回调 + """ trigger_id = dash.ctx.triggered_id if trigger_id == {'index': 'delete', 'type': 'job-operation-button'} or ( trigger_id == 'job-list-table' and recently_clicked_dropdown_item_title == '删除'): @@ -519,7 +532,7 @@ def job_delete_modal(operation_click, dropdown_click, {'job_ids': job_ids} ] - return [dash.no_update] * 3 + raise PreventUpdate @app.callback( @@ -531,6 +544,9 @@ def job_delete_modal(operation_click, dropdown_click, prevent_initial_call=True ) def job_delete_confirm(delete_confirm, job_ids_data): + """ + 删除定时任务弹窗确认回调,实现删除操作 + """ if delete_confirm: params = job_ids_data @@ -548,24 +564,33 @@ def job_delete_confirm(delete_confirm, job_ids_data): fuc.FefferyFancyMessage('删除失败', type='error') ] - return [dash.no_update] * 3 + raise PreventUpdate @app.callback( - [Output('job_to_job_log-modal', 'visible'), - Output('job_to_job_log-modal', 'title'), - Output('job_log-job_name-input', 'value', allow_duplicate=True), - Output('job_log-job_group-select', 'options'), - Output('job_log-search', 'nClicks'), - Output('api-check-token', 'data', allow_duplicate=True)], - [Input({'type': 'job-operation-log', 'index': ALL}, 'nClicks'), - Input('job-list-table', 'nClicksDropdownItem')], - [State('job-list-table', 'recentlyClickedDropdownItemTitle'), - State('job-list-table', 'recentlyDropdownItemClickedRow'), - State('job_log-search', 'nClicks')], + output=dict( + job_log_modal_visible=Output('job_to_job_log-modal', 'visible'), + job_log_modal_title=Output('job_to_job_log-modal', 'title'), + job_log_job_name=Output('job_log-job_name-input', 'value', allow_duplicate=True), + job_log_job_group_options=Output('job_log-job_group-select', 'options'), + job_log_search_nclick=Output('job_log-search', 'nClicks'), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True) + ), + inputs=dict( + operation_click=Input({'type': 'job-operation-log', 'index': ALL}, 'nClicks'), + dropdown_click=Input('job-list-table', 'nClicksDropdownItem') + ), + state=dict( + recently_clicked_dropdown_item_title=State('job-list-table', 'recentlyClickedDropdownItemTitle'), + recently_dropdown_item_clicked_row=State('job-list-table', 'recentlyDropdownItemClickedRow'), + job_log_search_nclick=State('job_log-search', 'nClicks') + ), prevent_initial_call=True ) def job_to_job_log_modal(operation_click, dropdown_click, recently_clicked_dropdown_item_title, recently_dropdown_item_clicked_row, job_log_search_nclick): + """ + 显示定时任务对应调度日志表格弹窗回调 + """ trigger_id = dash.ctx.triggered_id if trigger_id == {'index': 'log', 'type': 'job-operation-log'} or (trigger_id == 'job-list-table' and recently_clicked_dropdown_item_title == '调度日志'): @@ -576,25 +601,25 @@ def job_to_job_log_modal(operation_click, dropdown_click, recently_clicked_dropd option_table = [dict(label=item.get('dict_label'), value=item.get('dict_value')) for item in data] if trigger_id == 'job-list-table' and recently_clicked_dropdown_item_title == '调度日志': - return [ - True, - '任务调度日志', - recently_dropdown_item_clicked_row.get('job_name'), - option_table, - job_log_search_nclick + 1 if job_log_search_nclick else 1, - {'timestamp': time.time()}, - ] - - return [ - True, - '任务调度日志', - None, - option_table, - job_log_search_nclick + 1 if job_log_search_nclick else 1, - {'timestamp': time.time()}, - ] + return dict( + job_log_modal_visible=True, + job_log_modal_title='任务调度日志', + job_log_job_name=recently_dropdown_item_clicked_row.get('job_name'), + job_log_job_group_options=option_table, + job_log_search_nclick=job_log_search_nclick + 1 if job_log_search_nclick else 1, + api_check_token_trigger={'timestamp': time.time()} + ) + + return dict( + job_log_modal_visible=True, + job_log_modal_title='任务调度日志', + job_log_job_name=None, + job_log_job_group_options=option_table, + job_log_search_nclick=job_log_search_nclick + 1 if job_log_search_nclick else 1, + api_check_token_trigger={'timestamp': time.time()} + ) - return [dash.no_update] * 6 + raise PreventUpdate @app.callback( @@ -606,6 +631,9 @@ def job_to_job_log_modal(operation_click, dropdown_click, recently_clicked_dropd prevent_initial_call=True ) def export_job_list(export_click): + """ + 导出定时任务信息回调 + """ if export_click: export_job_res = export_job_list_api({}) if export_job_res.status_code == 200: @@ -625,7 +653,7 @@ def export_job_list(export_click): fuc.FefferyFancyMessage('导出失败', type='error') ] - return [dash.no_update] * 4 + raise PreventUpdate @app.callback( @@ -634,8 +662,11 @@ def export_job_list(export_click): prevent_initial_call=True ) def reset_job_export_status(data): + """ + 导出完成后重置下载组件数据回调,防止重复下载文件 + """ time.sleep(0.5) if data: return None - return dash.no_update + raise PreventUpdate diff --git a/dash-fastapi-frontend/callbacks/monitor_c/job_c/job_log_c.py b/dash-fastapi-frontend/callbacks/monitor_c/job_c/job_log_c.py index 61e05408c0756495123169aac26ba1636d34b78b..7b827ac3bee4527dead485064278e7c161bfddcd 100644 --- a/dash-fastapi-frontend/callbacks/monitor_c/job_c/job_log_c.py +++ b/dash-fastapi-frontend/callbacks/monitor_c/job_c/job_log_c.py @@ -4,6 +4,7 @@ import uuid import json from dash import dcc from dash.dependencies import Input, Output, State, ALL +from dash.exceptions import PreventUpdate import feffery_utils_components as fuc from server import app @@ -12,23 +13,32 @@ from api.dict import query_dict_data_list_api @app.callback( - [Output('job_log-list-table', 'data', allow_duplicate=True), - Output('job_log-list-table', 'pagination', allow_duplicate=True), - Output('job_log-list-table', 'key'), - Output('job_log-list-table', 'selectedRowKeys'), - Output('api-check-token', 'data', allow_duplicate=True)], - [Input('job_log-search', 'nClicks'), - Input('job_log-refresh', 'nClicks'), - Input('job_log-list-table', 'pagination'), - Input('job_log-operations-store', 'data')], - [State('job_log-job_name-input', 'value'), - State('job_log-job_group-select', 'value'), - State('job_log-status-select', 'value'), - State('job_log-create_time-range', 'value'), - State('job_log-button-perms-container', 'data')], + output=dict( + job_log_table_data=Output('job_log-list-table', 'data', allow_duplicate=True), + job_log_table_pagination=Output('job_log-list-table', 'pagination', allow_duplicate=True), + job_log_table_key=Output('job_log-list-table', 'key'), + job_log_table_selectedrowkeys=Output('job_log-list-table', 'selectedRowKeys'), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True) + ), + inputs=dict( + search_click=Input('job_log-search', 'nClicks'), + refresh_click=Input('job_log-refresh', 'nClicks'), + pagination=Input('job_log-list-table', 'pagination'), + operations=Input('job_log-operations-store', 'data') + ), + state=dict( + job_name=State('job_log-job_name-input', 'value'), + job_group=State('job_log-job_group-select', 'value'), + status_select=State('job_log-status-select', 'value'), + create_time_range=State('job_log-create_time-range', 'value'), + button_perms=State('job_log-button-perms-container', 'data') + ), prevent_initial_call=True ) def get_job_log_table_data(search_click, refresh_click, pagination, operations, job_name, job_group, status_select, create_time_range, button_perms): + """ + 获取定时任务对应调度日志表格数据回调(进行表格相关增删查改操作后均会触发此回调) + """ create_time_start = None create_time_end = None @@ -93,13 +103,26 @@ def get_job_log_table_data(search_click, refresh_click, pagination, operations, } if 'monitor:job:query' in button_perms else {}, ] - return [table_data, table_pagination, str(uuid.uuid4()), None, {'timestamp': time.time()}] + return dict( + job_log_table_data=table_data, + job_log_table_pagination=table_pagination, + job_log_table_key=str(uuid.uuid4()), + job_log_table_selectedrowkeys=None, + api_check_token_trigger={'timestamp': time.time()} + ) - return [dash.no_update, dash.no_update, dash.no_update, dash.no_update, {'timestamp': time.time()}] + return dict( + job_log_table_data=dash.no_update, + job_log_table_pagination=dash.no_update, + job_log_table_key=dash.no_update, + job_log_table_selectedrowkeys=dash.no_update, + api_check_token_trigger={'timestamp': time.time()} + ) - return [dash.no_update] * 5 + raise PreventUpdate +# 重置定时任务调度日志搜索表单数据回调 app.clientside_callback( ''' (reset_click) => { @@ -119,6 +142,7 @@ app.clientside_callback( ) +# 隐藏/显示定时任务调度日志搜索表单回调 app.clientside_callback( ''' (hidden_click, hidden_status) => { @@ -140,51 +164,45 @@ app.clientside_callback( @app.callback( - [Output('job_log-modal', 'visible', allow_duplicate=True), - Output('job_log-modal', 'title'), - Output('job_log-job_name-text', 'children'), - Output('job_log-job_group-text', 'children'), - Output('job_log-job_executor-text', 'children'), - Output('job_log-invoke_target-text', 'children'), - Output('job_log-job_args-text', 'children'), - Output('job_log-job_kwargs-text', 'children'), - Output('job_log-job_trigger-text', 'children'), - Output('job_log-job_message-text', 'children'), - Output('job_log-status-text', 'children'), - Output('job_log-create_time-text', 'children'), - Output('job_log-exception_info-text', 'children'), - Output('api-check-token', 'data', allow_duplicate=True)], - Input('job_log-list-table', 'nClicksButton'), - [State('job_log-list-table', 'clickedContent'), - State('job_log-list-table', 'recentlyButtonClickedRow')], + output=dict( + modal_visible=Output('job_log-modal', 'visible', allow_duplicate=True), + modal_title=Output('job_log-modal', 'title'), + form_value=Output({'type': 'job_log-form-value', 'index': ALL}, 'children'), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True) + ), + inputs=dict( + button_click=Input('job_log-list-table', 'nClicksButton') + ), + state=dict( + clicked_content=State('job_log-list-table', 'clickedContent'), + recently_button_clicked_row=State('job_log-list-table', 'recentlyButtonClickedRow') + ), prevent_initial_call=True ) def add_edit_job_log_modal(button_click, clicked_content, recently_button_clicked_row): if button_click: + # 获取所有输出表单项对应value的index + form_value_list = [x['id']['index'] for x in dash.ctx.outputs_list[-2]] job_log_id = int(recently_button_clicked_row['key']) job_log_info_res = get_job_log_detail_api(job_log_id=job_log_id) if job_log_info_res['code'] == 200: job_log_info = job_log_info_res['data'] - return [ - True, - '任务执行日志详情', - job_log_info.get('job_name'), - job_log_info.get('job_group'), - job_log_info.get('job_executor'), - job_log_info.get('invoke_target'), - job_log_info.get('job_args'), - job_log_info.get('job_kwargs'), - job_log_info.get('job_trigger'), - job_log_info.get('job_message'), - '成功' if job_log_info.get('status') == '0' else '失败', - job_log_info.get('create_time'), - job_log_info.get('exception_info'), - {'timestamp': time.time()}, - ] + job_log_info['status'] = '成功' if job_log_info.get('status') == '0' else '失败' + return dict( + modal_visible=True, + modal_title='任务执行日志详情', + form_value=[job_log_info.get(k) for k in form_value_list], + api_check_token_trigger={'timestamp': time.time()} + ) - return [dash.no_update] * 13 + [{'timestamp': time.time()}] + return dict( + modal_visible=dash.no_update, + modal_title=dash.no_update, + form_value=[dash.no_update] * len(form_value_list), + api_check_token_trigger={'timestamp': time.time()} + ) - return [dash.no_update] * 14 + raise PreventUpdate @app.callback( @@ -193,17 +211,18 @@ def add_edit_job_log_modal(button_click, clicked_content, recently_button_clicke prevent_initial_call=True ) def change_job_log_delete_button_status(table_rows_selected): + """ + 根据选择的表格数据行数控制删除按钮状态回调 + """ outputs_list = dash.ctx.outputs_list if outputs_list: if table_rows_selected: - if len(table_rows_selected) > 1: - return False return False return True - return dash.no_update + raise PreventUpdate @app.callback( @@ -215,6 +234,9 @@ def change_job_log_delete_button_status(table_rows_selected): prevent_initial_call=True ) def job_log_delete_modal(operation_click, selected_row_keys): + """ + 显示删除或清空定时任务调度日志二次确认弹窗回调 + """ trigger_id = dash.ctx.triggered_id if trigger_id.index in ['delete', 'clear']: if trigger_id.index == 'delete': @@ -233,7 +255,7 @@ def job_log_delete_modal(operation_click, selected_row_keys): {'oper_type': 'clear', 'job_log_ids': ''} ] - return [dash.no_update] * 3 + raise PreventUpdate @app.callback( @@ -245,6 +267,9 @@ def job_log_delete_modal(operation_click, selected_row_keys): prevent_initial_call=True ) def job_log_delete_confirm(delete_confirm, job_log_ids_data): + """ + 删除或清空定时任务调度日志弹窗确认回调,实现删除或清空操作 + """ if delete_confirm: oper_type = job_log_ids_data.get('oper_type') @@ -279,7 +304,7 @@ def job_log_delete_confirm(delete_confirm, job_log_ids_data): fuc.FefferyFancyMessage('删除失败', type='error') ] - return [dash.no_update] * 3 + raise PreventUpdate @app.callback( @@ -291,6 +316,9 @@ def job_log_delete_confirm(delete_confirm, job_log_ids_data): prevent_initial_call=True ) def export_job_log_list(export_click): + """ + 导出定时任务调度日志信息回调 + """ if export_click: export_job_log_res = export_job_log_list_api({}) if export_job_log_res.status_code == 200: @@ -310,7 +338,7 @@ def export_job_log_list(export_click): fuc.FefferyFancyMessage('导出失败', type='error') ] - return [dash.no_update] * 4 + raise PreventUpdate @app.callback( @@ -319,9 +347,12 @@ def export_job_log_list(export_click): prevent_initial_call=True ) def reset_job_log_export_status(data): + """ + 导出完成后重置下载组件数据回调,防止重复下载文件 + """ time.sleep(0.5) if data: return None - return dash.no_update + raise PreventUpdate diff --git a/dash-fastapi-frontend/callbacks/monitor_c/logininfor_c.py b/dash-fastapi-frontend/callbacks/monitor_c/logininfor_c.py index 754ed98a6af7f6260c35d8e391ccc87659bad48b..1971c5b6cefd2bf0161c209c2b1c7645b76a4d97 100644 --- a/dash-fastapi-frontend/callbacks/monitor_c/logininfor_c.py +++ b/dash-fastapi-frontend/callbacks/monitor_c/logininfor_c.py @@ -3,6 +3,7 @@ import time import uuid from dash import dcc from dash.dependencies import Input, Output, State, ALL +from dash.exceptions import PreventUpdate import feffery_utils_components as fuc from server import app @@ -10,23 +11,32 @@ from api.log import get_login_log_list_api, delete_login_log_api, clear_login_lo @app.callback( - [Output('login_log-list-table', 'data', allow_duplicate=True), - Output('login_log-list-table', 'pagination', allow_duplicate=True), - Output('login_log-list-table', 'key'), - Output('login_log-list-table', 'selectedRowKeys'), - Output('api-check-token', 'data', allow_duplicate=True)], - [Input('login_log-search', 'nClicks'), - Input('login_log-refresh', 'nClicks'), - Input('login_log-list-table', 'pagination'), - Input('login_log-operations-store', 'data')], - [State('login_log-ipaddr-input', 'value'), - State('login_log-user_name-input', 'value'), - State('login_log-status-select', 'value'), - State('login_log-login_time-range', 'value'), - State('login_log-button-perms-container', 'data')], + output=dict( + login_log_table_data=Output('login_log-list-table', 'data', allow_duplicate=True), + login_log_table_pagination=Output('login_log-list-table', 'pagination', allow_duplicate=True), + login_log_table_key=Output('login_log-list-table', 'key'), + login_log_table_selectedrowkeys=Output('login_log-list-table', 'selectedRowKeys'), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True) + ), + inputs=dict( + search_click=Input('login_log-search', 'nClicks'), + refresh_click=Input('login_log-refresh', 'nClicks'), + pagination=Input('login_log-list-table', 'pagination'), + operations=Input('login_log-operations-store', 'data') + ), + state=dict( + ipaddr=State('login_log-ipaddr-input', 'value'), + user_name=State('login_log-user_name-input', 'value'), + status_select=State('login_log-status-select', 'value'), + login_time_range=State('login_log-login_time-range', 'value'), + button_perms=State('login_log-button-perms-container', 'data') + ), prevent_initial_call=True ) def get_login_log_table_data(search_click, refresh_click, pagination, operations, ipaddr, user_name, status_select, login_time_range, button_perms): + """ + 获取登录日志表格数据回调(进行表格相关增删查改操作后均会触发此回调) + """ login_time_start = None login_time_end = None @@ -72,13 +82,26 @@ def get_login_log_table_data(search_click, refresh_click, pagination, operations item['status'] = dict(tag='失败', color='volcano') item['key'] = str(item['info_id']) - return [table_data, table_pagination, str(uuid.uuid4()), None, {'timestamp': time.time()}] + return dict( + login_log_table_data=table_data, + login_log_table_pagination=table_pagination, + login_log_table_key=str(uuid.uuid4()), + login_log_table_selectedrowkeys=None, + api_check_token_trigger={'timestamp': time.time()} + ) - return [dash.no_update, dash.no_update, dash.no_update, dash.no_update, {'timestamp': time.time()}] + return dict( + login_log_table_data=dash.no_update, + login_log_table_pagination=dash.no_update, + login_log_table_key=dash.no_update, + login_log_table_selectedrowkeys=dash.no_update, + api_check_token_trigger={'timestamp': time.time()} + ) - return [dash.no_update] * 5 + raise PreventUpdate +# 重置登录日志搜索表单数据回调 app.clientside_callback( ''' (reset_click) => { @@ -98,6 +121,7 @@ app.clientside_callback( ) +# 隐藏/显示登录日志搜索表单回调 app.clientside_callback( ''' (hidden_click, hidden_status) => { @@ -124,17 +148,18 @@ app.clientside_callback( prevent_initial_call=True ) def change_login_log_delete_button_status(table_rows_selected): + """ + 根据选择的表格数据行数控制删除按钮状态回调 + """ outputs_list = dash.ctx.outputs_list if outputs_list: if table_rows_selected: - if len(table_rows_selected) > 1: - return False return False return True - return dash.no_update + raise PreventUpdate @app.callback( @@ -143,6 +168,9 @@ def change_login_log_delete_button_status(table_rows_selected): prevent_initial_call=True ) def change_login_log_unlock_button_status(table_rows_selected): + """ + 根据选择的表格数据行数控制解锁按钮状态回调 + """ outputs_list = dash.ctx.outputs_list if outputs_list: if table_rows_selected: @@ -153,7 +181,7 @@ def change_login_log_unlock_button_status(table_rows_selected): return True - return dash.no_update + raise PreventUpdate @app.callback( @@ -165,6 +193,9 @@ def change_login_log_unlock_button_status(table_rows_selected): prevent_initial_call=True ) def login_log_delete_modal(operation_click, selected_row_keys): + """ + 显示删除或清空登录日志二次确认弹窗回调 + """ trigger_id = dash.ctx.triggered_id if trigger_id.index in ['delete', 'clear']: if trigger_id.index == 'delete': @@ -183,7 +214,7 @@ def login_log_delete_modal(operation_click, selected_row_keys): {'oper_type': 'clear', 'info_ids': ''} ] - return [dash.no_update] * 3 + raise PreventUpdate @app.callback( @@ -195,6 +226,9 @@ def login_log_delete_modal(operation_click, selected_row_keys): prevent_initial_call=True ) def login_log_delete_confirm(delete_confirm, info_ids_data): + """ + 删除或清空登录日志弹窗确认回调,实现删除或清空操作 + """ if delete_confirm: oper_type = info_ids_data.get('oper_type') @@ -229,7 +263,7 @@ def login_log_delete_confirm(delete_confirm, info_ids_data): fuc.FefferyFancyMessage('删除失败', type='error') ] - return [dash.no_update] * 3 + raise PreventUpdate @app.callback( @@ -241,6 +275,9 @@ def login_log_delete_confirm(delete_confirm, info_ids_data): prevent_initial_call=True ) def export_login_log_list(export_click): + """ + 导出登录日志信息回调 + """ if export_click: export_login_log_res = export_login_log_list_api({}) if export_login_log_res.status_code == 200: @@ -260,7 +297,7 @@ def export_login_log_list(export_click): fuc.FefferyFancyMessage('导出失败', type='error') ] - return [dash.no_update] * 4 + raise PreventUpdate @app.callback( @@ -269,12 +306,15 @@ def export_login_log_list(export_click): prevent_initial_call=True ) def reset_login_log_export_status(data): + """ + 导出完成后重置下载组件数据回调,防止重复下载文件 + """ time.sleep(0.5) if data: return None - return dash.no_update + raise PreventUpdate @app.callback( @@ -285,6 +325,9 @@ def reset_login_log_export_status(data): prevent_initial_call=True ) def unlock_user(unlock_click, selected_rows): + """ + 解锁用户回调 + """ if unlock_click: user_name = selected_rows[0].get('user_name') unlock_info_res = unlock_user_api(dict(user_name=user_name)) @@ -300,4 +343,4 @@ def unlock_user(unlock_click, selected_rows): fuc.FefferyFancyMessage('解锁失败', type='error') ] - return [dash.no_update] * 2 + raise PreventUpdate diff --git a/dash-fastapi-frontend/callbacks/monitor_c/online_c.py b/dash-fastapi-frontend/callbacks/monitor_c/online_c.py index eacbc75d6f0fbeaf90d4dbe7bb1d7e3ffd06981a..8a63b4559e305ce66ef201bbca3d23d3b78b13a2 100644 --- a/dash-fastapi-frontend/callbacks/monitor_c/online_c.py +++ b/dash-fastapi-frontend/callbacks/monitor_c/online_c.py @@ -2,6 +2,7 @@ import dash import time import uuid from dash.dependencies import Input, Output, State, ALL +from dash.exceptions import PreventUpdate import feffery_utils_components as fuc from server import app @@ -9,21 +10,30 @@ from api.online import get_online_list_api, force_logout_online_api, batch_logou @app.callback( - [Output('online-list-table', 'data', allow_duplicate=True), - Output('online-list-table', 'pagination', allow_duplicate=True), - Output('online-list-table', 'key'), - Output('online-list-table', 'selectedRowKeys'), - Output('api-check-token', 'data', allow_duplicate=True)], - [Input('online-search', 'nClicks'), - Input('online-refresh', 'nClicks'), - Input('online-list-table', 'pagination'), - Input('online-operations-store', 'data')], - [State('online-ipaddr-input', 'value'), - State('online-user_name-input', 'value'), - State('online-button-perms-container', 'data')], + output=dict( + online_table_data=Output('online-list-table', 'data', allow_duplicate=True), + online_table_pagination=Output('online-list-table', 'pagination', allow_duplicate=True), + online_table_key=Output('online-list-table', 'key'), + online_table_selectedrowkeys=Output('online-list-table', 'selectedRowKeys'), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True) + ), + inputs=dict( + search_click=Input('online-search', 'nClicks'), + refresh_click=Input('online-refresh', 'nClicks'), + pagination=Input('online-list-table', 'pagination'), + operations=Input('online-operations-store', 'data') + ), + state=dict( + ipaddr=State('online-ipaddr-input', 'value'), + user_name=State('online-user_name-input', 'value'), + button_perms=State('online-button-perms-container', 'data') + ), prevent_initial_call=True ) def get_online_table_data(search_click, refresh_click, pagination, operations, ipaddr, user_name, button_perms): + """ + 获取在线用户表格数据回调(进行表格相关增删查改操作后均会触发此回调) + """ query_params = dict( ipaddr=ipaddr, user_name=user_name, @@ -60,13 +70,26 @@ def get_online_table_data(search_click, refresh_click, pagination, operations, i } if 'monitor:online:forceLogout' in button_perms else {}, ] - return [table_data, table_pagination, str(uuid.uuid4()), None, {'timestamp': time.time()}] + return dict( + online_table_data=table_data, + online_table_pagination=table_pagination, + online_table_key=str(uuid.uuid4()), + online_table_selectedrowkeys=None, + api_check_token_trigger= {'timestamp': time.time()} + ) - return [dash.no_update, dash.no_update, dash.no_update, dash.no_update, {'timestamp': time.time()}] + return dict( + online_table_data=dash.no_update, + online_table_pagination=dash.no_update, + online_table_key=dash.no_update, + online_table_selectedrowkeys=dash.no_update, + api_check_token_trigger={'timestamp': time.time()} + ) - return [dash.no_update] * 5 + raise PreventUpdate +# 重置在线用户搜索表单数据回调 app.clientside_callback( ''' (reset_click) => { @@ -84,6 +107,7 @@ app.clientside_callback( ) +# 隐藏/显示在线用户搜索表单回调 app.clientside_callback( ''' (hidden_click, hidden_status) => { @@ -110,6 +134,9 @@ app.clientside_callback( prevent_initial_call=True ) def change_online_edit_delete_button_status(table_rows_selected): + """ + 根据选择的表格数据行数控制批量强退按钮状态回调 + """ outputs_list = dash.ctx.outputs_list if outputs_list: if table_rows_selected: @@ -118,7 +145,7 @@ def change_online_edit_delete_button_status(table_rows_selected): return True - return dash.no_update + raise PreventUpdate @app.callback( @@ -134,6 +161,9 @@ def change_online_edit_delete_button_status(table_rows_selected): ) def online_delete_modal(operation_click, button_click, selected_row_keys, clicked_content, recently_button_clicked_row): + """ + 显示强退在线用户二次确认弹窗回调 + """ trigger_id = dash.ctx.triggered_id if trigger_id == {'index': 'delete', 'type': 'online-operation-button'} or ( trigger_id == 'online-list-table' and clicked_content == '强退'): @@ -154,7 +184,7 @@ def online_delete_modal(operation_click, button_click, {'session_ids': session_ids, 'logout_type': logout_type} ] - return [dash.no_update] * 3 + raise PreventUpdate @app.callback( @@ -166,6 +196,9 @@ def online_delete_modal(operation_click, button_click, prevent_initial_call=True ) def online_delete_confirm(delete_confirm, session_ids_data): + """ + 强退在线用户弹窗确认回调,实现强退操作 + """ if delete_confirm: params = dict(session_ids=session_ids_data.get('session_ids')) @@ -187,4 +220,4 @@ def online_delete_confirm(delete_confirm, session_ids_data): fuc.FefferyFancyMessage('强退失败', type='error') ] - return [dash.no_update] * 3 + raise PreventUpdate diff --git a/dash-fastapi-frontend/callbacks/monitor_c/operlog_c.py b/dash-fastapi-frontend/callbacks/monitor_c/operlog_c.py index e45503f1516463adee6e65d531a56b15eaf3e180..4bd6aa333bbd2493a8d69c07fb35f9b3a9527cf9 100644 --- a/dash-fastapi-frontend/callbacks/monitor_c/operlog_c.py +++ b/dash-fastapi-frontend/callbacks/monitor_c/operlog_c.py @@ -4,6 +4,7 @@ import uuid import json from dash import dcc from dash.dependencies import Input, Output, State, ALL +from dash.exceptions import PreventUpdate import feffery_utils_components as fuc from server import app @@ -12,24 +13,33 @@ from api.dict import query_dict_data_list_api @app.callback( - [Output('operation_log-list-table', 'data', allow_duplicate=True), - Output('operation_log-list-table', 'pagination', allow_duplicate=True), - Output('operation_log-list-table', 'key'), - Output('operation_log-list-table', 'selectedRowKeys'), - Output('api-check-token', 'data', allow_duplicate=True)], - [Input('operation_log-search', 'nClicks'), - Input('operation_log-refresh', 'nClicks'), - Input('operation_log-list-table', 'pagination'), - Input('operation_log-operations-store', 'data')], - [State('operation_log-title-input', 'value'), - State('operation_log-oper_name-input', 'value'), - State('operation_log-business_type-select', 'value'), - State('operation_log-status-select', 'value'), - State('operation_log-oper_time-range', 'value'), - State('operation_log-button-perms-container', 'data')], + output=dict( + operation_log_table_data=Output('operation_log-list-table', 'data', allow_duplicate=True), + operation_log_table_pagination=Output('operation_log-list-table', 'pagination', allow_duplicate=True), + operation_log_table_key=Output('operation_log-list-table', 'key'), + operation_log_table_selectedrowkeys=Output('operation_log-list-table', 'selectedRowKeys'), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True) + ), + inputs=dict( + search_click=Input('operation_log-search', 'nClicks'), + refresh_click=Input('operation_log-refresh', 'nClicks'), + pagination=Input('operation_log-list-table', 'pagination'), + operations=Input('operation_log-operations-store', 'data') + ), + state=dict( + title=State('operation_log-title-input', 'value'), + oper_name=State('operation_log-oper_name-input', 'value'), + business_type=State('operation_log-business_type-select', 'value'), + status_select=State('operation_log-status-select', 'value'), + oper_time_range=State('operation_log-oper_time-range', 'value'), + button_perms=State('operation_log-button-perms-container', 'data') + ), prevent_initial_call=True ) def get_operation_log_table_data(search_click, refresh_click, pagination, operations, title, oper_name, business_type, status_select, oper_time_range, button_perms): + """ + 获取操作日志表格数据回调(进行表格相关增删查改操作后均会触发此回调) + """ oper_time_start = None oper_time_end = None @@ -97,13 +107,26 @@ def get_operation_log_table_data(search_click, refresh_click, pagination, operat } if 'monitor:operlog:query' in button_perms else {}, ] - return [table_data, table_pagination, str(uuid.uuid4()), None, {'timestamp': time.time()}] + return dict( + operation_log_table_data=table_data, + operation_log_table_pagination=table_pagination, + operation_log_table_key=str(uuid.uuid4()), + operation_log_table_selectedrowkeys=None, + api_check_token_trigger={'timestamp': time.time()} + ) - return [dash.no_update, dash.no_update, dash.no_update, dash.no_update, {'timestamp': time.time()}] + return dict( + operation_log_table_data=dash.no_update, + operation_log_table_pagination=dash.no_update, + operation_log_table_key=dash.no_update, + operation_log_table_selectedrowkeys=dash.no_update, + api_check_token_trigger={'timestamp': time.time()} + ) - return [dash.no_update] * 5 + raise PreventUpdate +# 重置操作日志搜索表单数据回调 app.clientside_callback( ''' (reset_click) => { @@ -124,6 +147,7 @@ app.clientside_callback( ) +# 隐藏/显示操作日志搜索表单回调 app.clientside_callback( ''' (hidden_click, hidden_status) => { @@ -145,26 +169,28 @@ app.clientside_callback( @app.callback( - [Output('operation_log-modal', 'visible', allow_duplicate=True), - Output('operation_log-modal', 'title'), - Output('operation_log-title-text', 'children'), - Output('operation_log-oper_url-text', 'children'), - Output('operation_log-login_info-text', 'children'), - Output('operation_log-request_method-text', 'children'), - Output('operation_log-method-text', 'children'), - Output('operation_log-oper_param-text', 'children'), - Output('operation_log-json_result-text', 'children'), - Output('operation_log-status-text', 'children'), - Output('operation_log-cost_time-text', 'children'), - Output('operation_log-oper_time-text', 'children'), - Output('api-check-token', 'data', allow_duplicate=True)], - Input('operation_log-list-table', 'nClicksButton'), - [State('operation_log-list-table', 'clickedContent'), - State('operation_log-list-table', 'recentlyButtonClickedRow')], + output=dict( + modal_visible=Output('operation_log-modal', 'visible', allow_duplicate=True), + modal_title=Output('operation_log-modal', 'title'), + form_value=Output({'type': 'operation_log-form-value', 'index': ALL}, 'children'), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True) + ), + inputs=dict( + button_click=Input('operation_log-list-table', 'nClicksButton') + ), + state=dict( + clicked_content=State('operation_log-list-table', 'clickedContent'), + recently_button_clicked_row=State('operation_log-list-table', 'recentlyButtonClickedRow') + ), prevent_initial_call=True ) def add_edit_operation_log_modal(button_click, clicked_content, recently_button_clicked_row): + """ + 显示操作日志详情弹窗回调 + """ if button_click: + # 获取所有输出表单项对应value的index + form_value_list = [x['id']['index'] for x in dash.ctx.outputs_list[-2]] oper_id = int(recently_button_clicked_row['key']) operation_log_info_res = get_operation_log_detail_api(oper_id=oper_id) if operation_log_info_res['code'] == 200: @@ -172,26 +198,24 @@ def add_edit_operation_log_modal(button_click, clicked_content, recently_button_ oper_name = operation_log_info.get('oper_name') if operation_log_info.get('oper_name') else '' oper_ip = operation_log_info.get('oper_ip') if operation_log_info.get('oper_ip') else '' oper_location = operation_log_info.get('oper_location') if operation_log_info.get('oper_location') else '' - login_info = f'{oper_name} / {oper_ip} / {oper_location}' - return [ - True, - '操作日志详情', - operation_log_info.get('title'), - operation_log_info.get('oper_url'), - login_info, - operation_log_info.get('request_method'), - operation_log_info.get('method'), - operation_log_info.get('oper_param'), - operation_log_info.get('json_result'), - '正常' if operation_log_info.get('status') == 0 else '失败', - f"{operation_log_info.get('cost_time')}毫秒", - operation_log_info.get('oper_time'), - {'timestamp': time.time()}, - ] + operation_log_info['login_info'] = f'{oper_name} / {oper_ip} / {oper_location}' + operation_log_info['status'] = '正常' if operation_log_info.get('status') == 0 else '失败' + operation_log_info['cost_time'] = f"{operation_log_info.get('cost_time')}毫秒" + return dict( + modal_visible=True, + modal_title='操作日志详情', + form_value=[operation_log_info.get(k) for k in form_value_list], + api_check_token_trigger={'timestamp': time.time()} + ) - return [dash.no_update] * 12 + [{'timestamp': time.time()}] + return dict( + modal_visible=dash.no_update, + modal_title=dash.no_update, + form_value=[dash.no_update] * len(form_value_list), + api_check_token_trigger={'timestamp': time.time()} + ) - return [dash.no_update] * 13 + raise PreventUpdate @app.callback( @@ -200,17 +224,18 @@ def add_edit_operation_log_modal(button_click, clicked_content, recently_button_ prevent_initial_call=True ) def change_operation_log_delete_button_status(table_rows_selected): + """ + 根据选择的表格数据行数控制删除按钮状态回调 + """ outputs_list = dash.ctx.outputs_list if outputs_list: if table_rows_selected: - if len(table_rows_selected) > 1: - return False return False return True - return dash.no_update + raise PreventUpdate @app.callback( @@ -222,6 +247,9 @@ def change_operation_log_delete_button_status(table_rows_selected): prevent_initial_call=True ) def operation_log_delete_modal(operation_click, selected_row_keys): + """ + 显示删除或清空操作日志二次确认弹窗回调 + """ trigger_id = dash.ctx.triggered_id if trigger_id.index in ['delete', 'clear']: if trigger_id.index == 'delete': @@ -240,7 +268,7 @@ def operation_log_delete_modal(operation_click, selected_row_keys): {'oper_type': 'clear', 'oper_ids': ''} ] - return [dash.no_update] * 3 + raise PreventUpdate @app.callback( @@ -252,6 +280,9 @@ def operation_log_delete_modal(operation_click, selected_row_keys): prevent_initial_call=True ) def operation_log_delete_confirm(delete_confirm, oper_ids_data): + """ + 删除或清空操作日志弹窗确认回调,实现删除或清空操作 + """ if delete_confirm: oper_type = oper_ids_data.get('oper_type') @@ -286,7 +317,7 @@ def operation_log_delete_confirm(delete_confirm, oper_ids_data): fuc.FefferyFancyMessage('删除失败', type='error') ] - return [dash.no_update] * 3 + raise PreventUpdate @app.callback( @@ -298,6 +329,9 @@ def operation_log_delete_confirm(delete_confirm, oper_ids_data): prevent_initial_call=True ) def export_operation_log_list(export_click): + """ + 导出操作日志信息回调 + """ if export_click: export_operation_log_res = export_operation_log_list_api({}) if export_operation_log_res.status_code == 200: @@ -317,7 +351,7 @@ def export_operation_log_list(export_click): fuc.FefferyFancyMessage('导出失败', type='error') ] - return [dash.no_update] * 4 + raise PreventUpdate @app.callback( @@ -326,9 +360,12 @@ def export_operation_log_list(export_click): prevent_initial_call=True ) def reset_operation_log_export_status(data): + """ + 导出完成后重置下载组件数据回调,防止重复下载文件 + """ time.sleep(0.5) if data: return None - return dash.no_update + raise PreventUpdate diff --git a/dash-fastapi-frontend/callbacks/system_c/config_c.py b/dash-fastapi-frontend/callbacks/system_c/config_c.py index b0d2ca4f675f719db4541cf9cc4a5be9ca054e79..47bf411f393be4afa1ad31e4d68422f8e95e725d 100644 --- a/dash-fastapi-frontend/callbacks/system_c/config_c.py +++ b/dash-fastapi-frontend/callbacks/system_c/config_c.py @@ -3,6 +3,7 @@ import time import uuid from dash import dcc from dash.dependencies import Input, Output, State, ALL +from dash.exceptions import PreventUpdate import feffery_utils_components as fuc from server import app @@ -10,23 +11,32 @@ from api.config import get_config_list_api, get_config_detail_api, add_config_ap @app.callback( - [Output('config-list-table', 'data', allow_duplicate=True), - Output('config-list-table', 'pagination', allow_duplicate=True), - Output('config-list-table', 'key'), - Output('config-list-table', 'selectedRowKeys'), - Output('api-check-token', 'data', allow_duplicate=True)], - [Input('config-search', 'nClicks'), - Input('config-refresh', 'nClicks'), - Input('config-list-table', 'pagination'), - Input('config-operations-store', 'data')], - [State('config-config_name-input', 'value'), - State('config-config_key-input', 'value'), - State('config-config_type-select', 'value'), - State('config-create_time-range', 'value'), - State('config-button-perms-container', 'data')], + output=dict( + config_table_data=Output('config-list-table', 'data', allow_duplicate=True), + config_table_pagination=Output('config-list-table', 'pagination', allow_duplicate=True), + config_table_key=Output('config-list-table', 'key'), + config_table_selectedrowkeys=Output('config-list-table', 'selectedRowKeys'), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True) + ), + inputs=dict( + search_click=Input('config-search', 'nClicks'), + refresh_click=Input('config-refresh', 'nClicks'), + pagination=Input('config-list-table', 'pagination'), + operations=Input('config-operations-store', 'data') + ), + state=dict( + config_name=State('config-config_name-input', 'value'), + config_key=State('config-config_key-input', 'value'), + config_type=State('config-config_type-select', 'value'), + create_time_range=State('config-create_time-range', 'value'), + button_perms=State('config-button-perms-container', 'data') + ), prevent_initial_call=True ) def get_config_table_data(search_click, refresh_click, pagination, operations, config_name, config_key, config_type, create_time_range, button_perms): + """ + 获取参数设置表格数据回调(进行表格相关增删查改操作后均会触发此回调) + """ create_time_start = None create_time_end = None if create_time_range: @@ -84,13 +94,26 @@ def get_config_table_data(search_click, refresh_click, pagination, operations, c } if 'system:config:remove' in button_perms else {}, ] - return [table_data, table_pagination, str(uuid.uuid4()), None, {'timestamp': time.time()}] + return dict( + config_table_data=table_data, + config_table_pagination=table_pagination, + config_table_key=str(uuid.uuid4()), + config_table_selectedrowkeys=None, + api_check_token_trigger={'timestamp': time.time()} + ) - return [dash.no_update, dash.no_update, dash.no_update, dash.no_update, {'timestamp': time.time()}] + return dict( + config_table_data=dash.no_update, + config_table_pagination=dash.no_update, + config_table_key=dash.no_update, + config_table_selectedrowkeys=dash.no_update, + api_check_token_trigger={'timestamp': time.time()} + ) - return [dash.no_update] * 5 + raise PreventUpdate +# 重置参数设置搜索表单数据回调 app.clientside_callback( ''' (reset_click) => { @@ -110,6 +133,7 @@ app.clientside_callback( ) +# 隐藏/显示参数设置搜索表单回调 app.clientside_callback( ''' (hidden_click, hidden_status) => { @@ -136,6 +160,9 @@ app.clientside_callback( prevent_initial_call=True ) def change_config_edit_button_status(table_rows_selected): + """ + 根据选择的表格数据行数控制编辑按钮状态回调 + """ outputs_list = dash.ctx.outputs_list if outputs_list: if table_rows_selected: @@ -146,7 +173,7 @@ def change_config_edit_button_status(table_rows_selected): return True - return dash.no_update + raise PreventUpdate @app.callback( @@ -155,55 +182,66 @@ def change_config_edit_button_status(table_rows_selected): prevent_initial_call=True ) def change_config_delete_button_status(table_rows_selected): + """ + 根据选择的表格数据行数控制删除按钮状态回调 + """ outputs_list = dash.ctx.outputs_list if outputs_list: if table_rows_selected: - if len(table_rows_selected) > 1: - return False return False return True - return dash.no_update + raise PreventUpdate @app.callback( - [Output('config-modal', 'visible', allow_duplicate=True), - Output('config-modal', 'title'), - Output('config-config_name', 'value'), - Output('config-config_key', 'value'), - Output('config-config_value', 'value'), - Output('config-config_type', 'value'), - Output('config-remark', 'value'), - Output('api-check-token', 'data', allow_duplicate=True), - Output('config-edit-id-store', 'data'), - Output('config-operations-store-bk', 'data')], - [Input({'type': 'config-operation-button', 'index': ALL}, 'nClicks'), - Input('config-list-table', 'nClicksButton')], - [State('config-list-table', 'selectedRowKeys'), - State('config-list-table', 'clickedContent'), - State('config-list-table', 'recentlyButtonClickedRow')], + output=dict( + modal_visible=Output('config-modal', 'visible', allow_duplicate=True), + modal_title=Output('config-modal', 'title'), + form_value=Output({'type': 'config-form-value', 'index': ALL}, 'value'), + form_label_validate_status=Output({'type': 'config-form-label', 'index': ALL, 'required': True}, 'validateStatus', allow_duplicate=True), + form_label_validate_info=Output({'type': 'config-form-label', 'index': ALL, 'required': True}, 'help', allow_duplicate=True), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True), + edit_row_info=Output('config-edit-id-store', 'data'), + modal_type=Output('config-operations-store-bk', 'data') + ), + inputs=dict( + operation_click=Input({'type': 'config-operation-button', 'index': ALL}, 'nClicks'), + button_click=Input('config-list-table', 'nClicksButton') + ), + state=dict( + selected_row_keys=State('config-list-table', 'selectedRowKeys'), + clicked_content=State('config-list-table', 'clickedContent'), + recently_button_clicked_row=State('config-list-table', 'recentlyButtonClickedRow') + ), prevent_initial_call=True ) def add_edit_config_modal(operation_click, button_click, selected_row_keys, clicked_content, recently_button_clicked_row): + """ + 显示新增或编辑参数设置弹窗回调 + """ trigger_id = dash.ctx.triggered_id if trigger_id == {'index': 'add', 'type': 'config-operation-button'} \ or trigger_id == {'index': 'edit', 'type': 'config-operation-button'} \ or (trigger_id == 'config-list-table' and clicked_content == '修改'): + # 获取所有输出表单项对应value的index + form_value_list = [x['id']['index'] for x in dash.ctx.outputs_list[2]] + # 获取所有输出表单项对应label的index + form_label_list = [x['id']['index'] for x in dash.ctx.outputs_list[3]] if trigger_id == {'index': 'add', 'type': 'config-operation-button'}: - return [ - True, - '新增参数', - None, - None, - None, - 'Y', - None, - dash.no_update, - None, - {'type': 'add'} - ] + config_info = dict(config_name=None, config_key=None, config_value=None, config_type='Y', remark=None) + return dict( + modal_visible=True, + modal_title='新增参数', + form_value=[config_info.get(k) for k in form_value_list], + form_label_validate_status=[None] * len(form_label_list), + form_label_validate_info=[None] * len(form_label_list), + api_check_token_trigger=dash.no_update, + edit_row_info=None, + modal_type={'type': 'add'} + ) elif trigger_id == {'index': 'edit', 'type': 'config-operation-button'} or (trigger_id == 'config-list-table' and clicked_content == '修改'): if trigger_id == {'index': 'edit', 'type': 'config-operation-button'}: config_id = int(','.join(selected_row_keys)) @@ -212,114 +250,112 @@ def add_edit_config_modal(operation_click, button_click, selected_row_keys, clic config_info_res = get_config_detail_api(config_id=config_id) if config_info_res['code'] == 200: config_info = config_info_res['data'] - return [ - True, - '编辑参数', - config_info.get('config_name'), - config_info.get('config_key'), - config_info.get('config_value'), - config_info.get('config_type'), - config_info.get('remark'), - {'timestamp': time.time()}, - config_info if config_info else None, - {'type': 'edit'} - ] - - return [dash.no_update] * 7 + [{'timestamp': time.time()}, None, None] + return dict( + modal_visible=True, + modal_title='编辑参数', + form_value=[config_info.get(k) for k in form_value_list], + form_label_validate_status=[None] * len(form_label_list), + form_label_validate_info=[None] * len(form_label_list), + api_check_token_trigger={'timestamp': time.time()}, + edit_row_info=config_info if config_info else None, + modal_type={'type': 'edit'} + ) + + return dict( + modal_visible=dash.no_update, + modal_title=dash.no_update, + form_value=[dash.no_update] * len(form_value_list), + form_label_validate_status=[dash.no_update] * len(form_label_list), + form_label_validate_info=[dash.no_update] * len(form_label_list), + api_check_token_trigger={'timestamp': time.time()}, + edit_row_info=None, + modal_type=None + ) - return [dash.no_update] * 8 + [None, None] + raise PreventUpdate @app.callback( - [Output('config-config_name-form-item', 'validateStatus'), - Output('config-config_key-form-item', 'validateStatus'), - Output('config-config_value-form-item', 'validateStatus'), - Output('config-config_name-form-item', 'help'), - Output('config-config_key-form-item', 'help'), - Output('config-config_value-form-item', 'help'), - Output('config-modal', 'visible'), - Output('config-operations-store', 'data', allow_duplicate=True), - Output('api-check-token', 'data', allow_duplicate=True), - Output('global-message-container', 'children', allow_duplicate=True)], - Input('config-modal', 'okCounts'), - [State('config-operations-store-bk', 'data'), - State('config-edit-id-store', 'data'), - State('config-config_name', 'value'), - State('config-config_key', 'value'), - State('config-config_value', 'value'), - State('config-config_type', 'value'), - State('config-remark', 'value')], + output=dict( + form_label_validate_status=Output({'type': 'config-form-label', 'index': ALL, 'required': True}, 'validateStatus', + allow_duplicate=True), + form_label_validate_info=Output({'type': 'config-form-label', 'index': ALL, 'required': True}, 'help', + allow_duplicate=True), + modal_visible=Output('config-modal', 'visible'), + operations=Output('config-operations-store', 'data', allow_duplicate=True), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True), + global_message_container=Output('global-message-container', 'children', allow_duplicate=True) + ), + inputs=dict( + confirm_trigger=Input('config-modal', 'okCounts') + ), + state=dict( + modal_type=State('config-operations-store-bk', 'data'), + edit_row_info=State('config-edit-id-store', 'data'), + form_value=State({'type': 'config-form-value', 'index': ALL}, 'value'), + form_label=State({'type': 'config-form-label', 'index': ALL, 'required': True}, 'label') + ), prevent_initial_call=True ) -def dict_type_confirm(confirm_trigger, operation_type, cur_config_info, config_name, config_key, config_value, config_type, remark): +def dict_type_confirm(confirm_trigger, modal_type, edit_row_info, form_value, form_label): + """ + 新增或编辑参数设置弹窗确认回调,实现新增或编辑操作 + """ if confirm_trigger: - if all([config_name, config_key, config_value]): - params_add = dict(config_name=config_name, config_key=config_key, config_value=config_value, - config_type=config_type, remark=remark) - params_edit = dict(config_id=cur_config_info.get('config_id') if cur_config_info else None, - config_name=config_name, config_key=config_key, config_value=config_value, - config_type=config_type, remark=remark) + # 获取所有输出表单项对应label的index + form_label_output_list = [x['id']['index'] for x in dash.ctx.outputs_list[0]] + # 获取所有输入表单项对应的value及label + form_value_state = {x['id']['index']: x.get('value') for x in dash.ctx.states_list[-2]} + form_label_state = {x['id']['index']: x.get('value') for x in dash.ctx.states_list[-1]} + if all([form_value_state.get(k) for k in form_label_output_list]): + params_add = form_value_state + params_edit = params_add.copy() + params_edit['config_id'] = edit_row_info.get('config_id') if edit_row_info else None api_res = {} - operation_type = operation_type.get('type') - if operation_type == 'add': + modal_type = modal_type.get('type') + if modal_type == 'add': api_res = add_config_api(params_add) - if operation_type == 'edit': + if modal_type == 'edit': api_res = edit_config_api(params_edit) if api_res.get('code') == 200: - if operation_type == 'add': - return [ - None, - None, - None, - None, - None, - None, - False, - {'type': 'add'}, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('新增成功', type='success') - ] - if operation_type == 'edit': - return [ - None, - None, - None, - None, - None, - None, - False, - {'type': 'edit'}, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('编辑成功', type='success') - ] - - return [ - None, - None, - None, - None, - None, - None, - dash.no_update, - dash.no_update, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('处理失败', type='error') - ] + if modal_type == 'add': + return dict( + form_label_validate_status=[None] * len(form_label_output_list), + form_label_validate_info=[None] * len(form_label_output_list), + modal_visible=False, + operations={'type': 'add'}, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('新增成功', type='success') + ) + if modal_type == 'edit': + return dict( + form_label_validate_status=[None] * len(form_label_output_list), + form_label_validate_info=[None] * len(form_label_output_list), + modal_visible=False, + operations={'type': 'edit'}, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('编辑成功', type='success') + ) + + return dict( + form_label_validate_status=[None] * len(form_label_output_list), + form_label_validate_info=[None] * len(form_label_output_list), + modal_visible=dash.no_update, + operations=dash.no_update, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('处理失败', type='error') + ) - return [ - None if config_name else 'error', - None if config_key else 'error', - None if config_value else 'error', - None if config_name else '请输入参数名称!', - None if config_key else '请输入参数键名!', - None if config_value else '请输入参数键值!', - dash.no_update, - dash.no_update, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('处理失败', type='error') - ] + return dict( + form_label_validate_status=[None if form_value_state.get(k) else 'error' for k in form_label_output_list], + form_label_validate_info=[None if form_value_state.get(k) else f'{form_label_state.get(k)}不能为空!' for k in form_label_output_list], + modal_visible=dash.no_update, + operations=dash.no_update, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('处理失败', type='error') + ) - return [dash.no_update] * 10 + raise PreventUpdate @app.callback( @@ -335,6 +371,9 @@ def dict_type_confirm(confirm_trigger, operation_type, cur_config_info, config_n ) def config_delete_modal(operation_click, button_click, selected_row_keys, clicked_content, recently_button_clicked_row): + """ + 显示删除参数设置二次确认弹窗回调 + """ trigger_id = dash.ctx.triggered_id if trigger_id == {'index': 'delete', 'type': 'config-operation-button'} or ( trigger_id == 'config-list-table' and clicked_content == '删除'): @@ -353,7 +392,7 @@ def config_delete_modal(operation_click, button_click, {'config_ids': config_ids} ] - return [dash.no_update] * 3 + raise PreventUpdate @app.callback( @@ -365,6 +404,9 @@ def config_delete_modal(operation_click, button_click, prevent_initial_call=True ) def config_delete_confirm(delete_confirm, config_ids_data): + """ + 删除参数设置弹窗确认回调,实现删除操作 + """ if delete_confirm: params = config_ids_data @@ -382,7 +424,7 @@ def config_delete_confirm(delete_confirm, config_ids_data): fuc.FefferyFancyMessage('删除失败', type='error') ] - return [dash.no_update] * 3 + raise PreventUpdate @app.callback( @@ -394,6 +436,9 @@ def config_delete_confirm(delete_confirm, config_ids_data): prevent_initial_call=True ) def export_config_list(export_click): + """ + 导出参数设置信息回调 + """ if export_click: export_config_res = export_config_list_api({}) if export_config_res.status_code == 200: @@ -413,7 +458,7 @@ def export_config_list(export_click): fuc.FefferyFancyMessage('导出失败', type='error') ] - return [dash.no_update] * 4 + raise PreventUpdate @app.callback( @@ -422,12 +467,15 @@ def export_config_list(export_click): prevent_initial_call=True ) def reset_config_export_status(data): + """ + 导出完成后重置下载组件数据回调,防止重复下载文件 + """ time.sleep(0.5) if data: return None - return dash.no_update + raise PreventUpdate @app.callback( @@ -437,6 +485,9 @@ def reset_config_export_status(data): prevent_initial_call=True ) def refresh_config_cache(refresh_click): + """ + 刷新缓存回调 + """ if refresh_click: refresh_info_res = refresh_config_api({}) if refresh_info_res.get('code') == 200: @@ -450,4 +501,4 @@ def refresh_config_cache(refresh_click): fuc.FefferyFancyMessage('刷新失败', type='error') ] - return [dash.no_update] * 2 + raise PreventUpdate diff --git a/dash-fastapi-frontend/callbacks/system_c/dept_c.py b/dash-fastapi-frontend/callbacks/system_c/dept_c.py index 8ce33e5491dc0e8e912071fa18ba4458c7218a42..660cc533e75a8b263be416062c4a72d73209a906 100644 --- a/dash-fastapi-frontend/callbacks/system_c/dept_c.py +++ b/dash-fastapi-frontend/callbacks/system_c/dept_c.py @@ -2,6 +2,7 @@ import dash import time import uuid from dash.dependencies import Input, Output, State, ALL +from dash.exceptions import PreventUpdate import feffery_utils_components as fuc from server import app @@ -11,23 +12,32 @@ from api.dept import get_dept_tree_api, get_dept_list_api, add_dept_api, edit_de @app.callback( - [Output('dept-list-table', 'data', allow_duplicate=True), - Output('dept-list-table', 'key'), - Output('dept-list-table', 'defaultExpandedRowKeys'), - Output('api-check-token', 'data', allow_duplicate=True), - Output('dept-fold', 'nClicks')], - [Input('dept-search', 'nClicks'), - Input('dept-refresh', 'nClicks'), - Input('dept-operations-store', 'data'), - Input('dept-fold', 'nClicks')], - [State('dept-dept_name-input', 'value'), - State('dept-status-select', 'value'), - State('dept-list-table', 'defaultExpandedRowKeys'), - State('dept-button-perms-container', 'data')], + output=dict( + dept_table_data=Output('dept-list-table', 'data', allow_duplicate=True), + dept_table_key=Output('dept-list-table', 'key'), + dept_table_defaultexpandedrowkeys=Output('dept-list-table', 'defaultExpandedRowKeys'), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True), + fold_click=Output('dept-fold', 'nClicks') + ), + inputs=dict( + search_click=Input('dept-search', 'nClicks'), + refresh_click=Input('dept-refresh', 'nClicks'), + operations=Input('dept-operations-store', 'data'), + fold_click=Input('dept-fold', 'nClicks') + ), + state=dict( + dept_name=State('dept-dept_name-input', 'value'), + status_select=State('dept-status-select', 'value'), + in_default_expanded_row_keys=State('dept-list-table', 'defaultExpandedRowKeys'), + button_perms=State('dept-button-perms-container', 'data') + ), prevent_initial_call=True ) -def get_dept_table_data(search_click, refresh_click, operations, fold_click, dept_name, status_select, in_default_expanded_row_keys, button_perms): - +def get_dept_table_data(search_click, refresh_click, operations, fold_click, dept_name, status_select, + in_default_expanded_row_keys, button_perms): + """ + 获取部门表格数据回调(进行表格相关增删查改操作后均会触发此回调) + """ query_params = dict( dept_name=dept_name, status=status_select @@ -92,15 +102,40 @@ def get_dept_table_data(search_click, refresh_click, operations, fold_click, dep if fold_click: if in_default_expanded_row_keys: - return [table_data_new, str(uuid.uuid4()), [], {'timestamp': time.time()}, None] + return dict( + dept_table_data=table_data_new, + dept_table_key=str(uuid.uuid4()), + dept_table_defaultexpandedrowkeys=[], + api_check_token_trigger={'timestamp': time.time()}, + fold_click=None + ) - return [table_data_new, str(uuid.uuid4()), default_expanded_row_keys, {'timestamp': time.time()}, None] + return dict( + dept_table_data=table_data_new, + dept_table_key=str(uuid.uuid4()), + dept_table_defaultexpandedrowkeys=default_expanded_row_keys, + api_check_token_trigger={'timestamp': time.time()}, + fold_click=None + ) - return [dash.no_update, dash.no_update, dash.no_update, {'timestamp': time.time()}, None] + return dict( + dept_table_data=dash.no_update, + dept_table_key=dash.no_update, + dept_table_defaultexpandedrowkeys=dash.no_update, + api_check_token_trigger={'timestamp': time.time()}, + fold_click=None + ) - return [dash.no_update] * 4 + [None] + return dict( + dept_table_data=dash.no_update, + dept_table_key=dash.no_update, + dept_table_defaultexpandedrowkeys=dash.no_update, + api_check_token_trigger=dash.no_update, + fold_click=None + ) +# 重置部门搜索表单数据回调 app.clientside_callback( ''' (reset_click) => { @@ -117,7 +152,7 @@ app.clientside_callback( prevent_initial_call=True ) - +# 隐藏/显示部门搜索表单回调 app.clientside_callback( ''' (hidden_click, hidden_status) => { @@ -139,29 +174,39 @@ app.clientside_callback( @app.callback( - [Output('dept-modal', 'visible', allow_duplicate=True), - Output('dept-modal', 'title'), - Output('dept-parent_id-div', 'hidden'), - Output('dept-parent_id', 'treeData'), - Output('dept-parent_id', 'value'), - Output('dept-dept_name', 'value'), - Output('dept-order_num', 'value'), - Output('dept-leader', 'value'), - Output('dept-phone', 'value'), - Output('dept-email', 'value'), - Output('dept-status', 'value'), - Output('api-check-token', 'data', allow_duplicate=True), - Output('dept-edit-id-store', 'data'), - Output('dept-operations-store-bk', 'data')], - [Input({'type': 'dept-operation-button', 'index': ALL}, 'nClicks'), - Input('dept-list-table', 'nClicksButton')], - [State('dept-list-table', 'clickedContent'), - State('dept-list-table', 'recentlyButtonClickedRow')], + output=dict( + modal_visible=Output('dept-modal', 'visible', allow_duplicate=True), + modal_title=Output('dept-modal', 'title'), + parent_id_div_ishidden=Output('dept-parent_id-div', 'hidden'), + parent_id_tree=Output({'type': 'dept-form-value', 'index': 'parent_id'}, 'treeData'), + form_value=Output({'type': 'dept-form-value', 'index': ALL}, 'value'), + form_label_validate_status=Output({'type': 'dept-form-label', 'index': ALL, 'required': True}, 'validateStatus', allow_duplicate=True), + form_label_validate_info=Output({'type': 'dept-form-label', 'index': ALL, 'required': True}, 'help', allow_duplicate=True), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True), + edit_row_info=Output('dept-edit-id-store', 'data'), + modal_type=Output('dept-operations-store-bk', 'data') + ), + inputs=dict( + operation_click=Input({'type': 'dept-operation-button', 'index': ALL}, 'nClicks'), + button_click=Input('dept-list-table', 'nClicksButton') + ), + state=dict( + clicked_content=State('dept-list-table', 'clickedContent'), + recently_button_clicked_row=State('dept-list-table', 'recentlyButtonClickedRow') + ), prevent_initial_call=True ) def add_edit_dept_modal(operation_click, button_click, clicked_content, recently_button_clicked_row): + """ + 显示新增或编辑部门弹窗回调 + """ trigger_id = dash.ctx.triggered_id - if trigger_id == {'index': 'add', 'type': 'dept-operation-button'} or (trigger_id == 'dept-list-table' and clicked_content != '删除'): + if trigger_id == {'index': 'add', 'type': 'dept-operation-button'} or ( + trigger_id == 'dept-list-table' and clicked_content != '删除'): + # 获取所有输出表单项对应value的index + form_value_list = [x['id']['index'] for x in dash.ctx.outputs_list[4]] + # 获取所有输出表单项对应label的index + form_label_list = [x['id']['index'] for x in dash.ctx.outputs_list[5]] dept_params = dict(dept_name='') if trigger_id == 'dept-list-table' and clicked_content == '修改': dept_params['dept_id'] = int(recently_button_clicked_row['key']) @@ -171,176 +216,143 @@ def add_edit_dept_modal(operation_click, button_click, clicked_content, recently if tree_info['code'] == 200: tree_data = tree_info['data'] - if trigger_id == {'index': 'add', 'type': 'dept-operation-button'}: - return [ - True, - '新增部门', - False, - tree_data, - None, - None, - None, - None, - None, - None, - '0', - {'timestamp': time.time()}, - None, - {'type': 'add'} - ] - elif trigger_id == 'dept-list-table' and clicked_content == '新增': - return [ - True, - '新增部门', - False, - tree_data, - str(recently_button_clicked_row['key']), - None, - None, - None, - None, - None, - '0', - {'timestamp': time.time()}, - None, - {'type': 'add'} - ] + if trigger_id == {'index': 'add', 'type': 'dept-operation-button'} or (trigger_id == 'dept-list-table' and clicked_content == '新增'): + dept_info = dict( + parent_id=None if trigger_id == {'index': 'add', 'type': 'dept-operation-button'} else str(recently_button_clicked_row['key']), + dept_name=None, + order_num=None, + leader=None, + phone=None, + email=None, + status='0', + ) + return dict( + modal_visible=True, + modal_title='新增部门', + parent_id_div_ishidden=False, + parent_id_tree=tree_data, + form_value=[dept_info.get(k) for k in form_value_list], + form_label_validate_status=[None] * len(form_label_list), + form_label_validate_info=[None] * len(form_label_list), + api_check_token_trigger={'timestamp': time.time()}, + edit_row_info=None, + modal_type={'type': 'add'} + ) elif trigger_id == 'dept-list-table' and clicked_content == '修改': dept_id = int(recently_button_clicked_row['key']) dept_info_res = get_dept_detail_api(dept_id=dept_id) if dept_info_res['code'] == 200: dept_info = dept_info_res['data'] - if dept_info.get('parent_id') == 0: - return [ - True, - '编辑部门', - True, - tree_data, - str(dept_info.get('parent_id')), - dept_info.get('dept_name'), - dept_info.get('order_num'), - dept_info.get('leader'), - dept_info.get('phone'), - dept_info.get('email'), - dept_info.get('status'), - {'timestamp': time.time()}, - dept_info, - {'type': 'edit'} - ] - else: - return [ - True, - '编辑部门', - False, - tree_data, - str(dept_info.get('parent_id')), - dept_info.get('dept_name'), - dept_info.get('order_num'), - dept_info.get('leader'), - dept_info.get('phone'), - dept_info.get('email'), - dept_info.get('status'), - {'timestamp': time.time()}, - dept_info, - {'type': 'edit'} - ] + return dict( + modal_visible=True, + modal_title='编辑部门', + parent_id_div_ishidden=dept_info.get('parent_id') == 0, + parent_id_tree=tree_data, + form_value=[dept_info.get(k) for k in form_value_list], + form_label_validate_status=[None] * len(form_label_list), + form_label_validate_info=[None] * len(form_label_list), + api_check_token_trigger={'timestamp': time.time()}, + edit_row_info=dept_info, + modal_type={'type': 'edit'} + ) - return [dash.no_update] * 11 + [{'timestamp': time.time()}, None, None] + return dict( + modal_visible=dash.no_update, + modal_title=dash.no_update, + parent_id_div_ishidden=dash.no_update, + parent_id_tree=dash.no_update, + form_value=[dash.no_update] * len(form_value_list), + form_label_validate_status=[dash.no_update] * len(form_label_list), + form_label_validate_info=[dash.no_update] * len(form_label_list), + api_check_token_trigger={'timestamp': time.time()}, + edit_row_info=None, + modal_type=None + ) - return [dash.no_update] * 12 + [None, None] + raise PreventUpdate @app.callback( - [Output('dept-parent_id-form-item', 'validateStatus'), - Output('dept-dept_name-form-item', 'validateStatus'), - Output('dept-order_num-form-item', 'validateStatus'), - Output('dept-parent_id-form-item', 'help'), - Output('dept-dept_name-form-item', 'help'), - Output('dept-order_num-form-item', 'help'), - Output('dept-modal', 'visible'), - Output('dept-operations-store', 'data', allow_duplicate=True), - Output('api-check-token', 'data', allow_duplicate=True), - Output('global-message-container', 'children', allow_duplicate=True)], - Input('dept-modal', 'okCounts'), - [State('dept-operations-store-bk', 'data'), - State('dept-edit-id-store', 'data'), - State('dept-parent_id', 'value'), - State('dept-dept_name', 'value'), - State('dept-order_num', 'value'), - State('dept-leader', 'value'), - State('dept-phone', 'value'), - State('dept-email', 'value'), - State('dept-status', 'value')], + output=dict( + form_label_validate_status=Output({'type': 'dept-form-label', 'index': ALL, 'required': True}, 'validateStatus', + allow_duplicate=True), + form_label_validate_info=Output({'type': 'dept-form-label', 'index': ALL, 'required': True}, 'help', + allow_duplicate=True), + modal_visible=Output('dept-modal', 'visible'), + operations=Output('dept-operations-store', 'data', allow_duplicate=True), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True), + global_message_container=Output('global-message-container', 'children', allow_duplicate=True) + ), + inputs=dict( + confirm_trigger=Input('dept-modal', 'okCounts') + ), + state=dict( + modal_type=State('dept-operations-store-bk', 'data'), + edit_row_info=State('dept-edit-id-store', 'data'), + form_value=State({'type': 'dept-form-value', 'index': ALL}, 'value'), + form_label=State({'type': 'dept-form-label', 'index': ALL, 'required': True}, 'label') + ), prevent_initial_call=True ) -def dept_confirm(confirm_trigger, operation_type, cur_dept_info, parent_id, dept_name, order_num, leader, phone, email, status): +def dept_confirm(confirm_trigger, modal_type, edit_row_info, form_value, form_label): + """ + 新增或编辑部门弹窗确认回调,实现新增或编辑操作 + """ if confirm_trigger: - if all([parent_id, dept_name, order_num]): - params_add = dict(parent_id=parent_id, dept_name=dept_name, order_num=order_num, leader=leader, phone=phone, - email=email, status=status) - params_edit = dict(dept_id=cur_dept_info.get('dept_id') if cur_dept_info else None, parent_id=parent_id, dept_name=dept_name, - order_num=order_num, leader=leader, phone=phone, email=email, status=status) + # 获取所有输出表单项对应label的index + form_label_output_list = [x['id']['index'] for x in dash.ctx.outputs_list[0]] + # 获取所有输入表单项对应的value及label + form_value_state = {x['id']['index']: x.get('value') for x in dash.ctx.states_list[-2]} + form_label_state = {x['id']['index']: x.get('value') for x in dash.ctx.states_list[-1]} + if all([form_value_state.get(k) for k in form_label_output_list]): + params_add = form_value_state + params_edit = params_add.copy() + params_edit['dept_id'] = edit_row_info.get('dept_id') if edit_row_info else None api_res = {} - operation_type = operation_type.get('type') - if operation_type == 'add': + modal_type = modal_type.get('type') + if modal_type == 'add': api_res = add_dept_api(params_add) - if operation_type == 'edit': + if modal_type == 'edit': api_res = edit_dept_api(params_edit) if api_res.get('code') == 200: - if operation_type == 'add': - return [ - None, - None, - None, - None, - None, - None, - False, - {'type': 'add'}, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('新增成功', type='success') - ] - if operation_type == 'edit': - return [ - None, - None, - None, - None, - None, - None, - False, - {'type': 'edit'}, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('编辑成功', type='success') - ] - - return [ - None, - None, - None, - None, - None, - None, - dash.no_update, - dash.no_update, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('处理失败', type='error') - ] - - return [ - None if parent_id else 'error', - None if dept_name else 'error', - None if order_num else 'error', - None if parent_id else '请选择上级部门!', - None if dept_name else '请输入部门名称!', - None if order_num else '请输入显示排序!', - dash.no_update, - dash.no_update, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('处理失败', type='error') - ] + if modal_type == 'add': + return dict( + form_label_validate_status=[None] * len(form_label_output_list), + form_label_validate_info=[None] * len(form_label_output_list), + modal_visible=False, + operations={'type': 'add'}, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('新增成功', type='success') + ) + if modal_type == 'edit': + return dict( + form_label_validate_status=[None] * len(form_label_output_list), + form_label_validate_info=[None] * len(form_label_output_list), + modal_visible=False, + operations={'type': 'edit'}, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('编辑成功', type='success') + ) + + return dict( + form_label_validate_status=[None] * len(form_label_output_list), + form_label_validate_info=[None] * len(form_label_output_list), + modal_visible=dash.no_update, + operations=dash.no_update, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('处理失败', type='error') + ) + + return dict( + form_label_validate_status=[None if form_value_state.get(k) else 'error' for k in form_label_output_list], + form_label_validate_info=[None if form_value_state.get(k) else f'{form_label_state.get(k)}不能为空!' for k in form_label_output_list], + modal_visible=dash.no_update, + operations=dash.no_update, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('处理失败', type='error') + ) - return [dash.no_update] * 10 + raise PreventUpdate @app.callback( @@ -353,6 +365,9 @@ def dept_confirm(confirm_trigger, operation_type, cur_dept_info, parent_id, dept prevent_initial_call=True ) def dept_delete_modal(button_click, clicked_content, recently_button_clicked_row): + """ + 显示删除部门二次确认弹窗回调 + """ if button_click: if clicked_content == '删除': @@ -366,7 +381,7 @@ def dept_delete_modal(button_click, clicked_content, recently_button_clicked_row {'dept_ids': dept_ids} ] - return [dash.no_update] * 3 + raise PreventUpdate @app.callback( @@ -378,6 +393,9 @@ def dept_delete_modal(button_click, clicked_content, recently_button_clicked_row prevent_initial_call=True ) def dept_delete_confirm(delete_confirm, dept_ids_data): + """ + 删除部门弹窗确认回调,实现删除操作 + """ if delete_confirm: params = dept_ids_data @@ -395,4 +413,4 @@ def dept_delete_confirm(delete_confirm, dept_ids_data): fuc.FefferyFancyMessage('删除失败', type='error') ] - return [dash.no_update] * 3 + raise PreventUpdate diff --git a/dash-fastapi-frontend/callbacks/system_c/dict_c/dict_c.py b/dash-fastapi-frontend/callbacks/system_c/dict_c/dict_c.py index 2cb608f4f18f491a8861f07c4a713573431c7712..a2b87cc66a58361a2a2e5fcf4b494f38e989b60a 100644 --- a/dash-fastapi-frontend/callbacks/system_c/dict_c/dict_c.py +++ b/dash-fastapi-frontend/callbacks/system_c/dict_c/dict_c.py @@ -3,6 +3,7 @@ import time import uuid from dash import dcc from dash.dependencies import Input, Output, State, ALL +from dash.exceptions import PreventUpdate import feffery_utils_components as fuc from server import app @@ -10,23 +11,32 @@ from api.dict import get_dict_type_list_api, get_all_dict_type_api, get_dict_typ @app.callback( - [Output('dict_type-list-table', 'data', allow_duplicate=True), - Output('dict_type-list-table', 'pagination', allow_duplicate=True), - Output('dict_type-list-table', 'key'), - Output('dict_type-list-table', 'selectedRowKeys'), - Output('api-check-token', 'data', allow_duplicate=True)], - [Input('dict_type-search', 'nClicks'), - Input('dict_type-refresh', 'nClicks'), - Input('dict_type-list-table', 'pagination'), - Input('dict_type-operations-store', 'data')], - [State('dict_type-dict_name-input', 'value'), - State('dict_type-dict_type-input', 'value'), - State('dict_type-status-select', 'value'), - State('dict_type-create_time-range', 'value'), - State('dict_type-button-perms-container', 'data')], + output=dict( + dict_type_table_data=Output('dict_type-list-table', 'data', allow_duplicate=True), + dict_type_table_pagination=Output('dict_type-list-table', 'pagination', allow_duplicate=True), + dict_type_table_key=Output('dict_type-list-table', 'key'), + dict_type_table_selectedrowkeys=Output('dict_type-list-table', 'selectedRowKeys'), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True) + ), + inputs=dict( + search_click=Input('dict_type-search', 'nClicks'), + refresh_click=Input('dict_type-refresh', 'nClicks'), + pagination=Input('dict_type-list-table', 'pagination'), + operations=Input('dict_type-operations-store', 'data') + ), + state=dict( + dict_name=State('dict_type-dict_name-input', 'value'), + dict_type=State('dict_type-dict_type-input', 'value'), + status_select=State('dict_type-status-select', 'value'), + create_time_range=State('dict_type-create_time-range', 'value'), + button_perms=State('dict_type-button-perms-container', 'data') + ), prevent_initial_call=True ) def get_dict_type_table_data(search_click, refresh_click, pagination, operations, dict_name, dict_type, status_select, create_time_range, button_perms): + """ + 获取字典类型表格数据回调(进行表格相关增删查改操作后均会触发此回调) + """ create_time_start = None create_time_end = None if create_time_range: @@ -88,13 +98,26 @@ def get_dict_type_table_data(search_click, refresh_click, pagination, operations } if 'system:dict:remove' in button_perms else {}, ] - return [table_data, table_pagination, str(uuid.uuid4()), None, {'timestamp': time.time()}] + return dict( + dict_type_table_data=table_data, + dict_type_table_pagination=table_pagination, + dict_type_table_key=str(uuid.uuid4()), + dict_type_table_selectedrowkeys=None, + api_check_token_trigger={'timestamp': time.time()} + ) - return [dash.no_update, dash.no_update, dash.no_update, dash.no_update, {'timestamp': time.time()}] + return dict( + dict_type_table_data=dash.no_update, + dict_type_table_pagination=dash.no_update, + dict_type_table_key=dash.no_update, + dict_type_table_selectedrowkeys=dash.no_update, + api_check_token_trigger={'timestamp': time.time()} + ) - return [dash.no_update] * 5 + raise PreventUpdate +# 重置字典类型搜索表单数据回调 app.clientside_callback( ''' (reset_click) => { @@ -114,6 +137,7 @@ app.clientside_callback( ) +# 隐藏/显示字典类型搜索表单回调 app.clientside_callback( ''' (hidden_click, hidden_status) => { @@ -140,6 +164,9 @@ app.clientside_callback( prevent_initial_call=True ) def change_dict_type_edit_button_status(table_rows_selected): + """ + 根据选择的表格数据行数控制编辑按钮状态回调 + """ outputs_list = dash.ctx.outputs_list if outputs_list: if table_rows_selected: @@ -150,7 +177,7 @@ def change_dict_type_edit_button_status(table_rows_selected): return True - return dash.no_update + raise PreventUpdate @app.callback( @@ -159,53 +186,66 @@ def change_dict_type_edit_button_status(table_rows_selected): prevent_initial_call=True ) def change_dict_type_delete_button_status(table_rows_selected): + """ + 根据选择的表格数据行数控制删除按钮状态回调 + """ outputs_list = dash.ctx.outputs_list if outputs_list: if table_rows_selected: - if len(table_rows_selected) > 1: - return False return False return True - return dash.no_update + raise PreventUpdate @app.callback( - [Output('dict_type-modal', 'visible', allow_duplicate=True), - Output('dict_type-modal', 'title'), - Output('dict_type-dict_name', 'value'), - Output('dict_type-dict_type', 'value'), - Output('dict_type-status', 'value'), - Output('dict_type-remark', 'value'), - Output('api-check-token', 'data', allow_duplicate=True), - Output('dict_type-edit-id-store', 'data'), - Output('dict_type-operations-store-bk', 'data')], - [Input({'type': 'dict_type-operation-button', 'index': ALL}, 'nClicks'), - Input('dict_type-list-table', 'nClicksButton')], - [State('dict_type-list-table', 'selectedRowKeys'), - State('dict_type-list-table', 'clickedContent'), - State('dict_type-list-table', 'recentlyButtonClickedRow')], + output=dict( + modal_visible=Output('dict_type-modal', 'visible', allow_duplicate=True), + modal_title=Output('dict_type-modal', 'title'), + form_value=Output({'type': 'dict_type-form-value', 'index': ALL}, 'value'), + form_label_validate_status=Output({'type': 'dict_type-form-label', 'index': ALL, 'required': True}, 'validateStatus', allow_duplicate=True), + form_label_validate_info=Output({'type': 'dict_type-form-label', 'index': ALL, 'required': True}, 'help', allow_duplicate=True), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True), + edit_row_info=Output('dict_type-edit-id-store', 'data'), + modal_type=Output('dict_type-operations-store-bk', 'data') + ), + inputs=dict( + operation_click=Input({'type': 'dict_type-operation-button', 'index': ALL}, 'nClicks'), + button_click=Input('dict_type-list-table', 'nClicksButton') + ), + state=dict( + selected_row_keys=State('dict_type-list-table', 'selectedRowKeys'), + clicked_content=State('dict_type-list-table', 'clickedContent'), + recently_button_clicked_row=State('dict_type-list-table', 'recentlyButtonClickedRow') + ), prevent_initial_call=True ) def add_edit_dict_type_modal(operation_click, button_click, selected_row_keys, clicked_content, recently_button_clicked_row): + """ + 显示新增或编辑字典类型弹窗回调 + """ trigger_id = dash.ctx.triggered_id if trigger_id == {'index': 'add', 'type': 'dict_type-operation-button'} \ or trigger_id == {'index': 'edit', 'type': 'dict_type-operation-button'} \ or (trigger_id == 'dict_type-list-table' and clicked_content == '修改'): + # 获取所有输出表单项对应value的index + form_value_list = [x['id']['index'] for x in dash.ctx.outputs_list[2]] + # 获取所有输出表单项对应label的index + form_label_list = [x['id']['index'] for x in dash.ctx.outputs_list[3]] if trigger_id == {'index': 'add', 'type': 'dict_type-operation-button'}: - return [ - True, - '新增字典类型', - None, - None, - '0', - None, - dash.no_update, - None, - {'type': 'add'} - ] + dict_type_info = dict(dict_name=None, dict_type=None, status='0', remark=None,) + return dict( + modal_visible=True, + modal_title='新增字典类型', + form_value=[dict_type_info.get(k) for k in form_value_list], + form_label_validate_status=[None] * len(form_label_list), + form_label_validate_info=[None] * len(form_label_list), + api_check_token_trigger=dash.no_update, + edit_row_info=None, + modal_type={'type': 'add'} + ) elif trigger_id == {'index': 'edit', 'type': 'dict_type-operation-button'} or (trigger_id == 'dict_type-list-table' and clicked_content == '修改'): if trigger_id == {'index': 'edit', 'type': 'dict_type-operation-button'}: dict_id = int(','.join(selected_row_keys)) @@ -214,100 +254,112 @@ def add_edit_dict_type_modal(operation_click, button_click, selected_row_keys, c dict_type_info_res = get_dict_type_detail_api(dict_id=dict_id) if dict_type_info_res['code'] == 200: dict_type_info = dict_type_info_res['data'] - return [ - True, - '编辑字典类型', - dict_type_info.get('dict_name'), - dict_type_info.get('dict_type'), - dict_type_info.get('status'), - dict_type_info.get('remark'), - {'timestamp': time.time()}, - dict_type_info if dict_type_info else None, - {'type': 'edit'} - ] - - return [dash.no_update] * 6 + [{'timestamp': time.time()}, None, None] + return dict( + modal_visible=True, + modal_title='编辑字典类型', + form_value=[dict_type_info.get(k) for k in form_value_list], + form_label_validate_status=[None] * len(form_label_list), + form_label_validate_info=[None] * len(form_label_list), + api_check_token_trigger={'timestamp': time.time()}, + edit_row_info=dict_type_info if dict_type_info else None, + modal_type={'type': 'edit'} + ) + + return dict( + modal_visible=dash.no_update, + modal_title=dash.no_update, + form_value=[dash.no_update] * len(form_value_list), + form_label_validate_status=[dash.no_update] * len(form_label_list), + form_label_validate_info=[dash.no_update] * len(form_label_list), + api_check_token_trigger={'timestamp': time.time()}, + edit_row_info=None, + modal_type=None + ) - return [dash.no_update] * 7 + [None, None] + raise PreventUpdate @app.callback( - [Output('dict_type-dict_name-form-item', 'validateStatus'), - Output('dict_type-dict_type-form-item', 'validateStatus'), - Output('dict_type-dict_name-form-item', 'help'), - Output('dict_type-dict_type-form-item', 'help'), - Output('dict_type-modal', 'visible'), - Output('dict_type-operations-store', 'data', allow_duplicate=True), - Output('api-check-token', 'data', allow_duplicate=True), - Output('global-message-container', 'children', allow_duplicate=True)], - Input('dict_type-modal', 'okCounts'), - [State('dict_type-operations-store-bk', 'data'), - State('dict_type-edit-id-store', 'data'), - State('dict_type-dict_name', 'value'), - State('dict_type-dict_type', 'value'), - State('dict_type-status', 'value'), - State('dict_type-remark', 'value')], + output=dict( + form_label_validate_status=Output({'type': 'dict_type-form-label', 'index': ALL, 'required': True}, 'validateStatus', + allow_duplicate=True), + form_label_validate_info=Output({'type': 'dict_type-form-label', 'index': ALL, 'required': True}, 'help', + allow_duplicate=True), + modal_visible=Output('dict_type-modal', 'visible'), + operations=Output('dict_type-operations-store', 'data', allow_duplicate=True), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True), + global_message_container=Output('global-message-container', 'children', allow_duplicate=True) + ), + inputs=dict( + confirm_trigger=Input('dict_type-modal', 'okCounts') + ), + state=dict( + modal_type=State('dict_type-operations-store-bk', 'data'), + edit_row_info=State('dict_type-edit-id-store', 'data'), + form_value=State({'type': 'dict_type-form-value', 'index': ALL}, 'value'), + form_label=State({'type': 'dict_type-form-label', 'index': ALL, 'required': True}, 'label') + ), prevent_initial_call=True ) -def dict_type_confirm(confirm_trigger, operation_type, cur_post_info, dict_name, dict_type, status, remark): +def dict_type_confirm(confirm_trigger, modal_type, edit_row_info, form_value, form_label): + """ + 新增或编字典类型弹窗确认回调,实现新增或编辑操作 + """ if confirm_trigger: - if all([dict_name, dict_type]): - params_add = dict(dict_name=dict_name, dict_type=dict_type, status=status, remark=remark) - params_edit = dict(dict_id=cur_post_info.get('dict_id') if cur_post_info else None, dict_name=dict_name, - dict_type=dict_type, status=status, remark=remark) + # 获取所有输出表单项对应label的index + form_label_output_list = [x['id']['index'] for x in dash.ctx.outputs_list[0]] + # 获取所有输入表单项对应的value及label + form_value_state = {x['id']['index']: x.get('value') for x in dash.ctx.states_list[-2]} + form_label_state = {x['id']['index']: x.get('value') for x in dash.ctx.states_list[-1]} + if all([form_value_state.get(k) for k in form_label_output_list]): + params_add = form_value_state + params_edit = params_add.copy() + params_edit['dict_id'] = edit_row_info.get('dict_id') if edit_row_info else None api_res = {} - operation_type = operation_type.get('type') - if operation_type == 'add': + modal_type = modal_type.get('type') + if modal_type == 'add': api_res = add_dict_type_api(params_add) - if operation_type == 'edit': + if modal_type == 'edit': api_res = edit_dict_type_api(params_edit) if api_res.get('code') == 200: - if operation_type == 'add': - return [ - None, - None, - None, - None, - False, - {'type': 'add'}, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('新增成功', type='success') - ] - if operation_type == 'edit': - return [ - None, - None, - None, - None, - False, - {'type': 'edit'}, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('编辑成功', type='success') - ] - - return [ - None, - None, - None, - None, - dash.no_update, - dash.no_update, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('处理失败', type='error') - ] + if modal_type == 'add': + return dict( + form_label_validate_status=[None] * len(form_label_output_list), + form_label_validate_info=[None] * len(form_label_output_list), + modal_visible=False, + operations={'type': 'add'}, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('新增成功', type='success') + ) + if modal_type == 'edit': + return dict( + form_label_validate_status=[None] * len(form_label_output_list), + form_label_validate_info=[None] * len(form_label_output_list), + modal_visible=False, + operations={'type': 'edit'}, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('编辑成功', type='success') + ) + + return dict( + form_label_validate_status=[None] * len(form_label_output_list), + form_label_validate_info=[None] * len(form_label_output_list), + modal_visible=dash.no_update, + operations=dash.no_update, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('处理失败', type='error') + ) - return [ - None if dict_name else 'error', - None if dict_type else 'error', - None if dict_name else '请输入字典名称!', - None if dict_type else '请输入字典类型!', - dash.no_update, - dash.no_update, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('处理失败', type='error') - ] + return dict( + form_label_validate_status=[None if form_value_state.get(k) else 'error' for k in form_label_output_list], + form_label_validate_info=[None if form_value_state.get(k) else f'{form_label_state.get(k)}不能为空!' for k in form_label_output_list], + modal_visible=dash.no_update, + operations=dash.no_update, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('处理失败', type='error') + ) - return [dash.no_update] * 8 + raise PreventUpdate @app.callback( @@ -323,6 +375,9 @@ def dict_type_confirm(confirm_trigger, operation_type, cur_post_info, dict_name, ) def dict_type_delete_modal(operation_click, button_click, selected_row_keys, clicked_content, recently_button_clicked_row): + """ + 显示删除字典类型二次确认弹窗回调 + """ trigger_id = dash.ctx.triggered_id if trigger_id == {'index': 'delete', 'type': 'dict_type-operation-button'} or ( trigger_id == 'dict_type-list-table' and clicked_content == '删除'): @@ -341,7 +396,7 @@ def dict_type_delete_modal(operation_click, button_click, {'dict_ids': dict_ids} ] - return [dash.no_update] * 3 + raise PreventUpdate @app.callback( @@ -353,6 +408,9 @@ def dict_type_delete_modal(operation_click, button_click, prevent_initial_call=True ) def dict_type_delete_confirm(delete_confirm, dict_ids_data): + """ + 删除字典类型弹窗确认回调,实现删除操作 + """ if delete_confirm: params = dict_ids_data @@ -370,23 +428,32 @@ def dict_type_delete_confirm(delete_confirm, dict_ids_data): fuc.FefferyFancyMessage('删除失败', type='error') ] - return [dash.no_update] * 3 + raise PreventUpdate @app.callback( - [Output('dict_type_to_dict_data-modal', 'visible'), - Output('dict_type_to_dict_data-modal', 'title'), - Output('dict_data-dict_type-select', 'options'), - Output('dict_data-dict_type-select', 'value', allow_duplicate=True), - Output('dict_data-search', 'nClicks'), - Output('api-check-token', 'data', allow_duplicate=True)], - Input('dict_type-list-table', 'nClicksButton'), - [State('dict_type-list-table', 'clickedContent'), - State('dict_type-list-table', 'recentlyButtonClickedRow'), - State('dict_data-search', 'nClicks')], + output=dict( + dict_data_modal_visible=Output('dict_type_to_dict_data-modal', 'visible'), + dict_data_modal_title=Output('dict_type_to_dict_data-modal', 'title'), + dict_data_select_options=Output('dict_data-dict_type-select', 'options'), + dict_data_select_value=Output('dict_data-dict_type-select', 'value', allow_duplicate=True), + dict_data_search_nclick=Output('dict_data-search', 'nClicks'), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True) + ), + inputs=dict( + button_click=Input('dict_type-list-table', 'nClicksButton') + ), + state=dict( + clicked_content=State('dict_type-list-table', 'clickedContent'), + recently_button_clicked_row=State('dict_type-list-table', 'recentlyButtonClickedRow'), + dict_data_search_nclick=State('dict_data-search', 'nClicks') + ), prevent_initial_call=True ) def dict_type_to_dict_data_modal(button_click, clicked_content, recently_button_clicked_row, dict_data_search_nclick): + """ + 显示字典类型对应数据表格弹窗回调 + """ if button_click and clicked_content == recently_button_clicked_row.get('dict_type').get('content'): all_dict_type_info = get_all_dict_type_api({}) @@ -394,25 +461,25 @@ def dict_type_to_dict_data_modal(button_click, clicked_content, recently_button_ all_dict_type = all_dict_type_info.get('data') dict_data_options = [dict(label=item.get('dict_name'), value=item.get('dict_type')) for item in all_dict_type] - return [ - True, - '字典数据', - dict_data_options, - recently_button_clicked_row.get('dict_type').get('content'), - dict_data_search_nclick + 1 if dict_data_search_nclick else 1, - {'timestamp': time.time()}, - ] + return dict( + dict_data_modal_visible=True, + dict_data_modal_title='字典数据', + dict_data_select_options=dict_data_options, + dict_data_select_value=recently_button_clicked_row.get('dict_type').get('content'), + dict_data_search_nclick=dict_data_search_nclick + 1 if dict_data_search_nclick else 1, + api_check_token_trigger={'timestamp': time.time()} + ) - return [ - True, - '字典数据', - [], - recently_button_clicked_row.get('dict_type').get('content'), - dict_data_search_nclick + 1 if dict_data_search_nclick else 1, - {'timestamp': time.time()}, - ] + return dict( + dict_data_modal_visible=True, + dict_data_modal_title='字典数据', + dict_data_select_options=[], + dict_data_select_value=recently_button_clicked_row.get('dict_type').get('content'), + dict_data_search_nclick=dict_data_search_nclick + 1 if dict_data_search_nclick else 1, + api_check_token_trigger={'timestamp': time.time()} + ) - return [dash.no_update] * 6 + raise PreventUpdate @app.callback( @@ -424,6 +491,9 @@ def dict_type_to_dict_data_modal(button_click, clicked_content, recently_button_ prevent_initial_call=True ) def export_dict_type_list(export_click): + """ + 导出字典类型信息回调 + """ if export_click: export_dict_type_res = export_dict_type_list_api({}) if export_dict_type_res.status_code == 200: @@ -443,7 +513,7 @@ def export_dict_type_list(export_click): fuc.FefferyFancyMessage('导出失败', type='error') ] - return [dash.no_update] * 4 + raise PreventUpdate @app.callback( @@ -452,12 +522,15 @@ def export_dict_type_list(export_click): prevent_initial_call=True ) def reset_dict_type_export_status(data): + """ + 导出完成后重置下载组件数据回调,防止重复下载文件 + """ time.sleep(0.5) if data: return None - return dash.no_update + raise PreventUpdate @app.callback( @@ -467,6 +540,9 @@ def reset_dict_type_export_status(data): prevent_initial_call=True ) def refresh_dict_cache(refresh_click): + """ + 刷新缓存回调 + """ if refresh_click: refresh_info_res = refresh_dict_api({}) if refresh_info_res.get('code') == 200: @@ -480,4 +556,4 @@ def refresh_dict_cache(refresh_click): fuc.FefferyFancyMessage('刷新失败', type='error') ] - return [dash.no_update] * 2 + raise PreventUpdate diff --git a/dash-fastapi-frontend/callbacks/system_c/dict_c/dict_data_c.py b/dash-fastapi-frontend/callbacks/system_c/dict_c/dict_data_c.py index c01bcb637d91cd60e70699a1ffc3749ce87f338e..f5c98bc29a8717b594822dd9cdd92561408df2be 100644 --- a/dash-fastapi-frontend/callbacks/system_c/dict_c/dict_data_c.py +++ b/dash-fastapi-frontend/callbacks/system_c/dict_c/dict_data_c.py @@ -3,6 +3,7 @@ import time import uuid from dash import dcc from dash.dependencies import Input, Output, State, ALL +from dash.exceptions import PreventUpdate import feffery_utils_components as fuc from server import app @@ -10,22 +11,31 @@ from api.dict import get_dict_data_list_api, get_dict_data_detail_api, add_dict_ @app.callback( - [Output('dict_data-list-table', 'data', allow_duplicate=True), - Output('dict_data-list-table', 'pagination', allow_duplicate=True), - Output('dict_data-list-table', 'key'), - Output('dict_data-list-table', 'selectedRowKeys'), - Output('api-check-token', 'data', allow_duplicate=True)], - [Input('dict_data-search', 'nClicks'), - Input('dict_data-refresh', 'nClicks'), - Input('dict_data-list-table', 'pagination'), - Input('dict_data-operations-store', 'data')], - [State('dict_data-dict_type-select', 'value'), - State('dict_data-dict_label-input', 'value'), - State('dict_data-status-select', 'value'), - State('dict_data-button-perms-container', 'data')], + output=dict( + dict_data_table_data=Output('dict_data-list-table', 'data', allow_duplicate=True), + dict_data_table_pagination=Output('dict_data-list-table', 'pagination', allow_duplicate=True), + dict_data_table_key=Output('dict_data-list-table', 'key'), + dict_data_table_selectedrowkeys=Output('dict_data-list-table', 'selectedRowKeys'), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True) + ), + inputs=dict( + search_click=Input('dict_data-search', 'nClicks'), + refresh_click=Input('dict_data-refresh', 'nClicks'), + pagination=Input('dict_data-list-table', 'pagination'), + operations=Input('dict_data-operations-store', 'data') + ), + state=dict( + dict_type=State('dict_data-dict_type-select', 'value'), + dict_label=State('dict_data-dict_label-input', 'value'), + status_select=State('dict_data-status-select', 'value'), + button_perms=State('dict_data-button-perms-container', 'data') + ), prevent_initial_call=True ) def get_dict_data_table_data(search_click, refresh_click, pagination, operations, dict_type, dict_label, status_select, button_perms): + """ + 获取字典数据表格数据回调(进行表格相关增删查改操作后均会触发此回调) + """ query_params = dict( dict_type=dict_type, @@ -74,13 +84,26 @@ def get_dict_data_table_data(search_click, refresh_click, pagination, operations } if 'system:dict:remove' in button_perms else {}, ] - return [table_data, table_pagination, str(uuid.uuid4()), None, {'timestamp': time.time()}] + return dict( + dict_data_table_data=table_data, + dict_data_table_pagination=table_pagination, + dict_data_table_key=str(uuid.uuid4()), + dict_data_table_selectedrowkeys=None, + api_check_token_trigger={'timestamp': time.time()} + ) - return [dash.no_update, dash.no_update, dash.no_update, dash.no_update, {'timestamp': time.time()}] + return dict( + dict_data_table_data=dash.no_update, + dict_data_table_pagination=dash.no_update, + dict_data_table_key=dash.no_update, + dict_data_table_selectedrowkeys=dash.no_update, + api_check_token_trigger={'timestamp': time.time()} + ) - return [dash.no_update] * 5 + raise PreventUpdate +# 重置字典数据搜索表单数据回调 app.clientside_callback( ''' (reset_click) => { @@ -98,6 +121,7 @@ app.clientside_callback( ) +# 隐藏/显示字典数据搜索表单回调 app.clientside_callback( ''' (hidden_click, hidden_status) => { @@ -124,6 +148,9 @@ app.clientside_callback( prevent_initial_call=True ) def change_dict_data_edit_button_status(table_rows_selected): + """ + 根据选择的表格数据行数控制编辑按钮状态回调 + """ outputs_list = dash.ctx.outputs_list if outputs_list: if table_rows_selected: @@ -134,7 +161,7 @@ def change_dict_data_edit_button_status(table_rows_selected): return True - return dash.no_update + raise PreventUpdate @app.callback( @@ -143,63 +170,77 @@ def change_dict_data_edit_button_status(table_rows_selected): prevent_initial_call=True ) def change_dict_data_delete_button_status(table_rows_selected): + """ + 根据选择的表格数据行数控制删除按钮状态回调 + """ outputs_list = dash.ctx.outputs_list if outputs_list: if table_rows_selected: - if len(table_rows_selected) > 1: - return False return False return True - return dash.no_update + raise PreventUpdate @app.callback( - [Output('dict_data-modal', 'visible', allow_duplicate=True), - Output('dict_data-modal', 'title'), - Output('dict_data-dict_type', 'value'), - Output('dict_data-dict_label', 'value'), - Output('dict_data-dict_value', 'value'), - Output('dict_data-css_class', 'value'), - Output('dict_data-dict_sort', 'value'), - Output('dict_data-list_class', 'value'), - Output('dict_data-status', 'value'), - Output('dict_data-remark', 'value'), - Output('api-check-token', 'data', allow_duplicate=True), - Output('dict_data-edit-id-store', 'data'), - Output('dict_data-operations-store-bk', 'data')], - [Input({'type': 'dict_data-operation-button', 'index': ALL}, 'nClicks'), - Input('dict_data-list-table', 'nClicksButton')], - [State('dict_data-list-table', 'selectedRowKeys'), - State('dict_data-list-table', 'clickedContent'), - State('dict_data-list-table', 'recentlyButtonClickedRow'), - State('dict_data-dict_type-select', 'value')], + output=dict( + modal_visible=Output('dict_data-modal', 'visible', allow_duplicate=True), + modal_title=Output('dict_data-modal', 'title'), + form_value=Output({'type': 'dict_data-form-value', 'index': ALL}, 'value'), + form_label_validate_status=Output({'type': 'dict_data-form-label', 'index': ALL, 'required': True}, 'validateStatus', allow_duplicate=True), + form_label_validate_info=Output({'type': 'dict_data-form-label', 'index': ALL, 'required': True}, 'help', allow_duplicate=True), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True), + edit_row_info=Output('dict_data-edit-id-store', 'data'), + modal_type=Output('dict_data-operations-store-bk', 'data') + ), + inputs=dict( + operation_click=Input({'type': 'dict_data-operation-button', 'index': ALL}, 'nClicks'), + button_click=Input('dict_data-list-table', 'nClicksButton') + ), + state=dict( + selected_row_keys=State('dict_data-list-table', 'selectedRowKeys'), + clicked_content=State('dict_data-list-table', 'clickedContent'), + recently_button_clicked_row=State('dict_data-list-table', 'recentlyButtonClickedRow'), + dict_type_select=State('dict_data-dict_type-select', 'value') + ), prevent_initial_call=True ) def add_edit_dict_data_modal(operation_click, button_click, selected_row_keys, clicked_content, recently_button_clicked_row, dict_type_select): + """ + 显示新增或编辑字典数据弹窗回调 + """ trigger_id = dash.ctx.triggered_id if trigger_id == {'index': 'add', 'type': 'dict_data-operation-button'} \ or trigger_id == {'index': 'edit', 'type': 'dict_data-operation-button'} \ or (trigger_id == 'dict_data-list-table' and clicked_content == '修改'): + # 获取所有输出表单项对应value的index + form_value_list = [x['id']['index'] for x in dash.ctx.outputs_list[2]] + # 获取所有输出表单项对应label的index + form_label_list = [x['id']['index'] for x in dash.ctx.outputs_list[3]] if trigger_id == {'index': 'add', 'type': 'dict_data-operation-button'}: - return [ - True, - '新增字典数据', - dict_type_select, - None, - None, - None, - 0, - 'default', - '0', - None, - dash.no_update, - None, - {'type': 'add'} - ] + dict_data_info = dict( + dict_type=dict_type_select, + dict_label=None, + dict_value=None, + css_class=None, + dict_sort=0, + list_class='default', + status='0', + remark=None + ) + return dict( + modal_visible=True, + modal_title='新增字典数据', + form_value=[dict_data_info.get(k) for k in form_value_list], + form_label_validate_status=[None] * len(form_label_list), + form_label_validate_info=[None] * len(form_label_list), + api_check_token_trigger=dash.no_update, + edit_row_info=None, + modal_type={'type': 'add'} + ) elif trigger_id == {'index': 'edit', 'type': 'dict_data-operation-button'} or (trigger_id == 'dict_data-list-table' and clicked_content == '修改'): if trigger_id == {'index': 'edit', 'type': 'dict_data-operation-button'}: dict_code = int(','.join(selected_row_keys)) @@ -208,117 +249,112 @@ def add_edit_dict_data_modal(operation_click, button_click, selected_row_keys, c dict_data_info_res = get_dict_data_detail_api(dict_code=dict_code) if dict_data_info_res['code'] == 200: dict_data_info = dict_data_info_res['data'] - return [ - True, - '编辑字典数据', - dict_data_info.get('dict_type'), - dict_data_info.get('dict_label'), - dict_data_info.get('dict_value'), - dict_data_info.get('css_class'), - dict_data_info.get('dict_sort'), - dict_data_info.get('list_class'), - dict_data_info.get('status'), - dict_data_info.get('remark'), - {'timestamp': time.time()}, - dict_data_info if dict_data_info else None, - {'type': 'edit'} - ] - - return [dash.no_update] * 10 + [{'timestamp': time.time()}, None, None] + return dict( + modal_visible=True, + modal_title='编辑字典数据', + form_value=[dict_data_info.get(k) for k in form_value_list], + form_label_validate_status=[None] * len(form_label_list), + form_label_validate_info=[None] * len(form_label_list), + api_check_token_trigger={'timestamp': time.time()}, + edit_row_info=dict_data_info if dict_data_info else None, + modal_type={'type': 'edit'} + ) + + return dict( + modal_visible=dash.no_update, + modal_title=dash.no_update, + form_value=[dash.no_update] * len(form_value_list), + form_label_validate_status=[dash.no_update] * len(form_label_list), + form_label_validate_info=[dash.no_update] * len(form_label_list), + api_check_token_trigger={'timestamp': time.time()}, + edit_row_info=None, + modal_type=None + ) - return [dash.no_update] * 11 + [None, None] + raise PreventUpdate @app.callback( - [Output('dict_data-dict_label-form-item', 'validateStatus'), - Output('dict_data-dict_value-form-item', 'validateStatus'), - Output('dict_data-dict_sort-form-item', 'validateStatus'), - Output('dict_data-dict_label-form-item', 'help'), - Output('dict_data-dict_value-form-item', 'help'), - Output('dict_data-dict_sort-form-item', 'help'), - Output('dict_data-modal', 'visible'), - Output('dict_data-operations-store', 'data', allow_duplicate=True), - Output('api-check-token', 'data', allow_duplicate=True), - Output('global-message-container', 'children', allow_duplicate=True)], - Input('dict_data-modal', 'okCounts'), - [State('dict_data-operations-store-bk', 'data'), - State('dict_data-edit-id-store', 'data'), - State('dict_data-dict_type', 'value'), - State('dict_data-dict_label', 'value'), - State('dict_data-dict_value', 'value'), - State('dict_data-css_class', 'value'), - State('dict_data-dict_sort', 'value'), - State('dict_data-list_class', 'value'), - State('dict_data-status', 'value'), - State('dict_data-remark', 'value')], + output=dict( + form_label_validate_status=Output({'type': 'dict_data-form-label', 'index': ALL, 'required': True}, 'validateStatus', + allow_duplicate=True), + form_label_validate_info=Output({'type': 'dict_data-form-label', 'index': ALL, 'required': True}, 'help', + allow_duplicate=True), + modal_visible=Output('dict_data-modal', 'visible'), + operations=Output('dict_data-operations-store', 'data', allow_duplicate=True), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True), + global_message_container=Output('global-message-container', 'children', allow_duplicate=True) + ), + inputs=dict( + confirm_trigger=Input('dict_data-modal', 'okCounts') + ), + state=dict( + modal_type=State('dict_data-operations-store-bk', 'data'), + edit_row_info=State('dict_data-edit-id-store', 'data'), + form_value=State({'type': 'dict_data-form-value', 'index': ALL}, 'value'), + form_label=State({'type': 'dict_data-form-label', 'index': ALL, 'required': True}, 'label') + ), prevent_initial_call=True ) -def dict_data_confirm(confirm_trigger, operation_type, cur_post_info, dict_type, dict_label, dict_value, css_class, dict_sort, list_class, status, remark): +def dict_data_confirm(confirm_trigger, modal_type, edit_row_info, form_value, form_label): + """ + 新增或编字典数据弹窗确认回调,实现新增或编辑操作 + """ if confirm_trigger: - if all([dict_label, dict_value, dict_sort]): - params_add = dict(dict_type=dict_type, dict_label=dict_label, dict_value=dict_value, css_class=css_class, dict_sort=dict_sort, list_class=list_class, status=status, remark=remark) - params_edit = dict(dict_code=cur_post_info.get('dict_code') if cur_post_info else None, dict_type=dict_type, dict_label=dict_label, dict_value=dict_value, css_class=css_class, dict_sort=dict_sort, list_class=list_class, status=status, remark=remark) + # 获取所有输出表单项对应label的index + form_label_output_list = [x['id']['index'] for x in dash.ctx.outputs_list[0]] + # 获取所有输入表单项对应的value及label + form_value_state = {x['id']['index']: x.get('value') for x in dash.ctx.states_list[-2]} + form_label_state = {x['id']['index']: x.get('value') for x in dash.ctx.states_list[-1]} + if all([form_value_state.get(k) for k in form_label_output_list]): + params_add = form_value_state + params_edit = params_add.copy() + params_edit['dict_code'] = edit_row_info.get('dict_code') if edit_row_info else None api_res = {} - operation_type = operation_type.get('type') - if operation_type == 'add': + modal_type = modal_type.get('type') + if modal_type == 'add': api_res = add_dict_data_api(params_add) - if operation_type == 'edit': + if modal_type == 'edit': api_res = edit_dict_data_api(params_edit) if api_res.get('code') == 200: - if operation_type == 'add': - return [ - None, - None, - None, - None, - None, - None, - False, - {'type': 'add'}, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('新增成功', type='success') - ] - if operation_type == 'edit': - return [ - None, - None, - None, - None, - None, - None, - False, - {'type': 'edit'}, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('编辑成功', type='success') - ] - - return [ - None, - None, - None, - None, - None, - None, - dash.no_update, - dash.no_update, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('处理失败', type='error') - ] + if modal_type == 'add': + return dict( + form_label_validate_status=[None] * len(form_label_output_list), + form_label_validate_info=[None] * len(form_label_output_list), + modal_visible=False, + operations={'type': 'add'}, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('新增成功', type='success') + ) + if modal_type == 'edit': + return dict( + form_label_validate_status=[None] * len(form_label_output_list), + form_label_validate_info=[None] * len(form_label_output_list), + modal_visible=False, + operations={'type': 'edit'}, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('编辑成功', type='success') + ) + + return dict( + form_label_validate_status=[None] * len(form_label_output_list), + form_label_validate_info=[None] * len(form_label_output_list), + modal_visible=dash.no_update, + operations=dash.no_update, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('处理失败', type='error') + ) - return [ - None if dict_label else 'error', - None if dict_value else 'error', - None if dict_sort else 'error', - None if dict_label else '请输入数据标签!', - None if dict_value else '请输入数据键值!', - None if dict_sort else '请输入显示排序!', - dash.no_update, - dash.no_update, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('处理失败', type='error') - ] + return dict( + form_label_validate_status=[None if form_value_state.get(k) else 'error' for k in form_label_output_list], + form_label_validate_info=[None if form_value_state.get(k) else f'{form_label_state.get(k)}不能为空!' for k in form_label_output_list], + modal_visible=dash.no_update, + operations=dash.no_update, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('处理失败', type='error') + ) - return [dash.no_update] * 10 + raise PreventUpdate @app.callback( @@ -334,6 +370,9 @@ def dict_data_confirm(confirm_trigger, operation_type, cur_post_info, dict_type, ) def dict_data_delete_modal(operation_click, button_click, selected_row_keys, clicked_content, recently_button_clicked_row): + """ + 显示删除字典数据二次确认弹窗回调 + """ trigger_id = dash.ctx.triggered_id if trigger_id == {'index': 'delete', 'type': 'dict_data-operation-button'} or ( trigger_id == 'dict_data-list-table' and clicked_content == '删除'): @@ -352,7 +391,7 @@ def dict_data_delete_modal(operation_click, button_click, {'dict_codes': dict_codes} ] - return [dash.no_update] * 3 + raise PreventUpdate @app.callback( @@ -364,6 +403,9 @@ def dict_data_delete_modal(operation_click, button_click, prevent_initial_call=True ) def dict_data_delete_confirm(delete_confirm, dict_codes_data): + """ + 删除字典数据弹窗确认回调,实现删除操作 + """ if delete_confirm: params = dict_codes_data @@ -381,7 +423,7 @@ def dict_data_delete_confirm(delete_confirm, dict_codes_data): fuc.FefferyFancyMessage('删除失败', type='error') ] - return [dash.no_update] * 3 + raise PreventUpdate @app.callback( @@ -394,6 +436,9 @@ def dict_data_delete_confirm(delete_confirm, dict_codes_data): prevent_initial_call=True ) def export_dict_data_list(export_click, dict_type): + """ + 导出字典数据信息回调 + """ if export_click: export_dict_data_res = export_dict_data_list_api(dict(dict_type=dict_type)) if export_dict_data_res.status_code == 200: @@ -413,7 +458,7 @@ def export_dict_data_list(export_click, dict_type): fuc.FefferyFancyMessage('导出失败', type='error') ] - return [dash.no_update] * 4 + raise PreventUpdate @app.callback( @@ -422,9 +467,12 @@ def export_dict_data_list(export_click, dict_type): prevent_initial_call=True ) def reset_dict_data_export_status(data): + """ + 导出完成后重置下载组件数据回调,防止重复下载文件 + """ time.sleep(0.5) if data: return None - return dash.no_update + raise PreventUpdate diff --git a/dash-fastapi-frontend/callbacks/system_c/menu_c/components_c/button_type_c.py b/dash-fastapi-frontend/callbacks/system_c/menu_c/components_c/button_type_c.py index 773a70d2ab4df2ed7f05af3a7e3b2046ccb88cca..53da181b9c4b5e6a0845201ea350138062f59f27 100644 --- a/dash-fastapi-frontend/callbacks/system_c/menu_c/components_c/button_type_c.py +++ b/dash-fastapi-frontend/callbacks/system_c/menu_c/components_c/button_type_c.py @@ -1,6 +1,7 @@ import dash import time from dash.dependencies import Input, Output, State +from dash.exceptions import PreventUpdate import feffery_utils_components as fuc from server import app @@ -8,94 +9,92 @@ from api.menu import add_menu_api, edit_menu_api @app.callback( - [Output('menu-parent_id-form-item', 'validateStatus', allow_duplicate=True), - Output('menu-menu_name-form-item', 'validateStatus', allow_duplicate=True), - Output('menu-order_num-form-item', 'validateStatus', allow_duplicate=True), - Output('menu-parent_id-form-item', 'help', allow_duplicate=True), - Output('menu-menu_name-form-item', 'help', allow_duplicate=True), - Output('menu-order_num-form-item', 'help', allow_duplicate=True), - Output('menu-modal', 'visible', allow_duplicate=True), - Output('menu-operations-store', 'data', allow_duplicate=True), - Output('api-check-token', 'data', allow_duplicate=True), - Output('global-message-container', 'children', allow_duplicate=True)], - Input('menu-modal-F-trigger', 'data'), - [State('menu-operations-store-bk', 'data'), - State('menu-edit-id-store', 'data'), - State('menu-parent_id', 'value'), - State('menu-menu_type', 'value'), - State('menu-icon', 'value'), - State('menu-menu_name', 'value'), - State('menu-order_num', 'value'), - State('button-menu-perms', 'value')], + output=dict( + form_validate=[ + Output('menu-parent_id-form-item', 'validateStatus', allow_duplicate=True), + Output('menu-menu_name-form-item', 'validateStatus', allow_duplicate=True), + Output('menu-order_num-form-item', 'validateStatus', allow_duplicate=True), + Output('menu-parent_id-form-item', 'help', allow_duplicate=True), + Output('menu-menu_name-form-item', 'help', allow_duplicate=True), + Output('menu-order_num-form-item', 'help', allow_duplicate=True) + ], + modal_visible=Output('menu-modal', 'visible', allow_duplicate=True), + operations=Output('menu-operations-store', 'data', allow_duplicate=True), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True), + global_message_container=Output('global-message-container', 'children', allow_duplicate=True) + ), + inputs=dict( + confirm_trigger=Input('menu-modal-F-trigger', 'data'), + ), + state=dict( + modal_type=State('menu-operations-store-bk', 'data'), + edit_row_info=State('menu-edit-id-store', 'data'), + parent_id=State('menu-parent_id', 'value'), + menu_type=State('menu-menu_type', 'value'), + icon=State('menu-icon', 'value'), + menu_name=State('menu-menu_name', 'value'), + order_num=State('menu-order_num', 'value'), + perms=State('button-menu-perms', 'value') + ), prevent_initial_call=True ) -def menu_confirm_button(confirm_trigger, operation_type, cur_menu_info, parent_id, menu_type, icon, menu_name, order_num, perms): +def menu_confirm_button(confirm_trigger, modal_type, edit_row_info, parent_id, menu_type, icon, menu_name, order_num, perms): + """ + 菜单类型为按钮时新增或编辑弹窗确认回调,实现新增或编辑操作 + """ if confirm_trigger: if all([parent_id, menu_name, order_num]): params_add = dict(parent_id=parent_id, menu_type=menu_type, icon=icon, menu_name=menu_name, order_num=order_num, perms=perms) - params_edit = dict(menu_id=cur_menu_info.get('menu_id') if cur_menu_info else None, parent_id=parent_id, menu_type=menu_type, icon=icon, + params_edit = dict(menu_id=edit_row_info.get('menu_id') if edit_row_info else None, parent_id=parent_id, menu_type=menu_type, icon=icon, menu_name=menu_name, order_num=order_num, perms=perms) api_res = {} - operation_type = operation_type.get('type') - if operation_type == 'add': + modal_type = modal_type.get('type') + if modal_type == 'add': api_res = add_menu_api(params_add) - if operation_type == 'edit': + if modal_type == 'edit': api_res = edit_menu_api(params_edit) if api_res.get('code') == 200: - if operation_type == 'add': - return [ - None, - None, - None, - None, - None, - None, - False, - {'type': 'add'}, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('新增成功', type='success') - ] - if operation_type == 'edit': - return [ - None, - None, - None, - None, - None, - None, - False, - {'type': 'edit'}, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('编辑成功', type='success') - ] - - return [ - None, - None, - None, - None, - None, - None, - dash.no_update, - dash.no_update, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('处理失败', type='error') - ] - - return [ - None if parent_id else 'error', - None if menu_name else 'error', - None if order_num else 'error', - None if parent_id else '请选择上级菜单!', - None if menu_name else '请输入菜单名称!', - None if order_num else '请输入显示排序!', - dash.no_update, - dash.no_update, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('处理失败', type='error') - ] + if modal_type == 'add': + return dict( + form_validate=[None] * 6, + modal_visible=False, + operations={'type': 'add'}, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('新增成功', type='success') + ) + if modal_type == 'edit': + return dict( + form_validate=[None] * 6, + modal_visible=False, + operations={'type': 'edit'}, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('编辑成功', type='success') + ) - return [dash.no_update] * 10 + return dict( + form_validate=[None] * 6, + modal_visible=dash.no_update, + operations=dash.no_update, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('处理失败', type='error') + ) + + return dict( + form_validate=[ + None if parent_id else 'error', + None if menu_name else 'error', + None if order_num else 'error', + None if parent_id else '请选择上级菜单!', + None if menu_name else '请输入菜单名称!', + None if order_num else '请输入显示排序!' + ], + modal_visible=dash.no_update, + operations=dash.no_update, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('处理失败', type='error') + ) + + raise PreventUpdate @app.callback( @@ -103,7 +102,10 @@ def menu_confirm_button(confirm_trigger, operation_type, cur_menu_info, parent_i Input('menu-edit-id-store', 'data') ) def set_edit_info(edit_info): + """ + 菜单类型为按钮时回显菜单数据回调 + """ if edit_info: return edit_info.get('perms') - return dash.no_update + raise PreventUpdate diff --git a/dash-fastapi-frontend/callbacks/system_c/menu_c/components_c/content_type_c.py b/dash-fastapi-frontend/callbacks/system_c/menu_c/components_c/content_type_c.py index 4b692103102f2895543edb825be8d0625b7e3d48..d18c71630026c0293bc6514de8879b13b652c9d6 100644 --- a/dash-fastapi-frontend/callbacks/system_c/menu_c/components_c/content_type_c.py +++ b/dash-fastapi-frontend/callbacks/system_c/menu_c/components_c/content_type_c.py @@ -1,6 +1,7 @@ import dash import time from dash.dependencies import Input, Output, State +from dash.exceptions import PreventUpdate import feffery_utils_components as fuc from server import app @@ -8,108 +9,100 @@ from api.menu import add_menu_api, edit_menu_api @app.callback( - [Output('menu-parent_id-form-item', 'validateStatus', allow_duplicate=True), - Output('menu-menu_name-form-item', 'validateStatus', allow_duplicate=True), - Output('menu-order_num-form-item', 'validateStatus', allow_duplicate=True), - Output('content-menu-path-form-item', 'validateStatus'), - Output('menu-parent_id-form-item', 'help', allow_duplicate=True), - Output('menu-menu_name-form-item', 'help', allow_duplicate=True), - Output('menu-order_num-form-item', 'help', allow_duplicate=True), - Output('content-menu-path-form-item', 'help'), - Output('menu-modal', 'visible', allow_duplicate=True), - Output('menu-operations-store', 'data', allow_duplicate=True), - Output('api-check-token', 'data', allow_duplicate=True), - Output('global-message-container', 'children', allow_duplicate=True)], - Input('menu-modal-M-trigger', 'data'), - [State('menu-operations-store-bk', 'data'), - State('menu-edit-id-store', 'data'), - State('menu-parent_id', 'value'), - State('menu-menu_type', 'value'), - State('menu-icon', 'value'), - State('menu-menu_name', 'value'), - State('menu-order_num', 'value'), - State('content-menu-is_frame', 'value'), - State('content-menu-path', 'value'), - State('content-menu-visible', 'value'), - State('content-menu-status', 'value')], + output=dict( + form_validate=[ + Output('menu-parent_id-form-item', 'validateStatus', allow_duplicate=True), + Output('menu-menu_name-form-item', 'validateStatus', allow_duplicate=True), + Output('menu-order_num-form-item', 'validateStatus', allow_duplicate=True), + Output('content-menu-path-form-item', 'validateStatus'), + Output('menu-parent_id-form-item', 'help', allow_duplicate=True), + Output('menu-menu_name-form-item', 'help', allow_duplicate=True), + Output('menu-order_num-form-item', 'help', allow_duplicate=True), + Output('content-menu-path-form-item', 'help'), + ], + modal_visible=Output('menu-modal', 'visible', allow_duplicate=True), + operations=Output('menu-operations-store', 'data', allow_duplicate=True), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True), + global_message_container=Output('global-message-container', 'children', allow_duplicate=True) + ), + inputs=dict( + confirm_trigger=Input('menu-modal-M-trigger', 'data') + ), + state=dict( + modal_type=State('menu-operations-store-bk', 'data'), + edit_row_info=State('menu-edit-id-store', 'data'), + parent_id=State('menu-parent_id', 'value'), + menu_type=State('menu-menu_type', 'value'), + icon=State('menu-icon', 'value'), + menu_name=State('menu-menu_name', 'value'), + order_num=State('menu-order_num', 'value'), + is_frame=State('content-menu-is_frame', 'value'), + path=State('content-menu-path', 'value'), + visible=State('content-menu-visible', 'value'), + status=State('content-menu-status', 'value') + ), prevent_initial_call=True ) -def menu_confirm_content(confirm_trigger, operation_type, cur_menu_info, parent_id, menu_type, icon, menu_name, order_num, is_frame, path, visible, status): +def menu_confirm_content(confirm_trigger, modal_type, edit_row_info, parent_id, menu_type, icon, menu_name, order_num, is_frame, path, visible, status): + """ + 菜单类型为目录时新增或编辑弹窗确认回调,实现新增或编辑操作 + """ if confirm_trigger: if all([parent_id, menu_name, order_num, path]): params_add = dict(parent_id=parent_id, menu_type=menu_type, icon=icon, menu_name=menu_name, order_num=order_num, is_frame=is_frame, path=path, visible=visible, status=status) - params_edit = dict(menu_id=cur_menu_info.get('menu_id') if cur_menu_info else None, parent_id=parent_id, menu_type=menu_type, icon=icon, + params_edit = dict(menu_id=edit_row_info.get('menu_id') if edit_row_info else None, parent_id=parent_id, menu_type=menu_type, icon=icon, menu_name=menu_name, order_num=order_num, is_frame=is_frame, path=path, visible=visible, status=status) api_res = {} - operation_type = operation_type.get('type') - if operation_type == 'add': + modal_type = modal_type.get('type') + if modal_type == 'add': api_res = add_menu_api(params_add) - if operation_type == 'edit': + if modal_type == 'edit': api_res = edit_menu_api(params_edit) if api_res.get('code') == 200: - if operation_type == 'add': - return [ - None, - None, - None, - None, - None, - None, - None, - None, - False, - {'type': 'add'}, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('新增成功', type='success') - ] - if operation_type == 'edit': - return [ - None, - None, - None, - None, - None, - None, - None, - None, - False, - {'type': 'edit'}, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('编辑成功', type='success') - ] - - return [ - None, - None, - None, - None, - None, - None, - None, - None, - dash.no_update, - dash.no_update, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('处理失败', type='error') - ] - - return [ - None if parent_id else 'error', - None if menu_name else 'error', - None if order_num else 'error', - None if path else 'error', - None if parent_id else '请选择上级菜单!', - None if menu_name else '请输入菜单名称!', - None if order_num else '请输入显示排序!', - None if path else '请输入路由地址!', - dash.no_update, - dash.no_update, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('处理失败', type='error') - ] + if modal_type == 'add': + return dict( + form_validate=[None] * 8, + modal_visible=False, + operations={'type': 'add'}, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('新增成功', type='success') + ) + if modal_type == 'edit': + return dict( + form_validate=[None] * 8, + modal_visible=False, + operations={'type': 'edit'}, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('编辑成功', type='success') + ) + + return dict( + form_validate=[None] * 8, + modal_visible=dash.no_update, + operations=dash.no_update, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('处理失败', type='error') + ) + + return dict( + form_validate=[ + None if parent_id else 'error', + None if menu_name else 'error', + None if order_num else 'error', + None if path else 'error', + None if parent_id else '请选择上级菜单!', + None if menu_name else '请输入菜单名称!', + None if order_num else '请输入显示排序!', + None if path else '请输入路由地址!', + ], + modal_visible=dash.no_update, + operations=dash.no_update, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('处理失败', type='error') + ) - return [dash.no_update] * 12 + raise PreventUpdate @app.callback( @@ -120,6 +113,9 @@ def menu_confirm_content(confirm_trigger, operation_type, cur_menu_info, parent_ Input('menu-edit-id-store', 'data') ) def set_edit_info(edit_info): + """ + 菜单类型为目录时回显菜单数据回调 + """ if edit_info: return [ edit_info.get('is_frame'), @@ -128,4 +124,4 @@ def set_edit_info(edit_info): edit_info.get('status') ] - return [dash.no_update] * 4 + raise PreventUpdate diff --git a/dash-fastapi-frontend/callbacks/system_c/menu_c/components_c/menu_type_c.py b/dash-fastapi-frontend/callbacks/system_c/menu_c/components_c/menu_type_c.py index 5ca9d4a7f96e6396f7eace93fd8ebe72cf018d7c..f37b79231973b06560bdb14fdd2e761dbd836edb 100644 --- a/dash-fastapi-frontend/callbacks/system_c/menu_c/components_c/menu_type_c.py +++ b/dash-fastapi-frontend/callbacks/system_c/menu_c/components_c/menu_type_c.py @@ -1,6 +1,7 @@ import dash import time from dash.dependencies import Input, Output, State +from dash.exceptions import PreventUpdate import feffery_utils_components as fuc from server import app @@ -8,114 +9,106 @@ from api.menu import add_menu_api, edit_menu_api @app.callback( - [Output('menu-parent_id-form-item', 'validateStatus', allow_duplicate=True), - Output('menu-menu_name-form-item', 'validateStatus', allow_duplicate=True), - Output('menu-order_num-form-item', 'validateStatus', allow_duplicate=True), - Output('menu-menu-path-form-item', 'validateStatus'), - Output('menu-parent_id-form-item', 'help', allow_duplicate=True), - Output('menu-menu_name-form-item', 'help', allow_duplicate=True), - Output('menu-order_num-form-item', 'help', allow_duplicate=True), - Output('menu-menu-path-form-item', 'help', allow_duplicate=True), - Output('menu-modal', 'visible'), - Output('menu-operations-store', 'data', allow_duplicate=True), - Output('api-check-token', 'data', allow_duplicate=True), - Output('global-message-container', 'children', allow_duplicate=True)], - Input('menu-modal-C-trigger', 'data'), - [State('menu-operations-store-bk', 'data'), - State('menu-edit-id-store', 'data'), - State('menu-parent_id', 'value'), - State('menu-menu_type', 'value'), - State('menu-icon', 'value'), - State('menu-menu_name', 'value'), - State('menu-order_num', 'value'), - State('menu-menu-is_frame', 'value'), - State('menu-menu-path', 'value'), - State('menu-menu-component', 'value'), - State('menu-menu-perms', 'value'), - State('menu-menu-query', 'value'), - State('menu-menu-is_cache', 'value'), - State('menu-menu-visible', 'value'), - State('menu-menu-status', 'value')], + output=dict( + form_validate=[ + Output('menu-parent_id-form-item', 'validateStatus', allow_duplicate=True), + Output('menu-menu_name-form-item', 'validateStatus', allow_duplicate=True), + Output('menu-order_num-form-item', 'validateStatus', allow_duplicate=True), + Output('menu-menu-path-form-item', 'validateStatus', allow_duplicate=True), + Output('menu-parent_id-form-item', 'help', allow_duplicate=True), + Output('menu-menu_name-form-item', 'help', allow_duplicate=True), + Output('menu-order_num-form-item', 'help', allow_duplicate=True), + Output('menu-menu-path-form-item', 'help', allow_duplicate=True), + ], + modal_visible=Output('menu-modal', 'visible', allow_duplicate=True), + operations=Output('menu-operations-store', 'data', allow_duplicate=True), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True), + global_message_container=Output('global-message-container', 'children', allow_duplicate=True) + ), + inputs=dict( + confirm_trigger=Input('menu-modal-C-trigger', 'data') + ), + state=dict( + modal_type=State('menu-operations-store-bk', 'data'), + edit_row_info=State('menu-edit-id-store', 'data'), + parent_id=State('menu-parent_id', 'value'), + menu_type=State('menu-menu_type', 'value'), + icon=State('menu-icon', 'value'), + menu_name=State('menu-menu_name', 'value'), + order_num=State('menu-order_num', 'value'), + is_frame=State('menu-menu-is_frame', 'value'), + path=State('menu-menu-path', 'value'), + component=State('menu-menu-component', 'value'), + perms=State('menu-menu-perms', 'value'), + query=State('menu-menu-query', 'value'), + is_cache=State('menu-menu-is_cache', 'value'), + visible=State('menu-menu-visible', 'value'), + status=State('menu-menu-status', 'value') + ), prevent_initial_call=True ) -def menu_confirm_menu(confirm_trigger, operation_type, cur_menu_info, parent_id, menu_type, icon, menu_name, order_num, is_frame, path, +def menu_confirm_menu(confirm_trigger, modal_type, edit_row_info, parent_id, menu_type, icon, menu_name, order_num, is_frame, path, component, perms, query, is_cache, visible, status): + """ + 菜单类型为菜单时新增或编辑弹窗确认回调,实现新增或编辑操作 + """ if confirm_trigger: if all([parent_id, menu_name, order_num, path]): params_add = dict(parent_id=parent_id, menu_type=menu_type, icon=icon, menu_name=menu_name, order_num=order_num, is_frame=is_frame, path=path, component=component, perms=perms, query=query, is_cache=is_cache, visible=visible, status=status) - params_edit = dict(menu_id=cur_menu_info.get('menu_id') if cur_menu_info else None, parent_id=parent_id, menu_type=menu_type, icon=icon, + params_edit = dict(menu_id=edit_row_info.get('menu_id') if edit_row_info else None, parent_id=parent_id, menu_type=menu_type, icon=icon, menu_name=menu_name, order_num=order_num, is_frame=is_frame, path=path, component=component, perms=perms, query=query, is_cache=is_cache, visible=visible, status=status) api_res = {} - operation_type = operation_type.get('type') - if operation_type == 'add': + modal_type = modal_type.get('type') + if modal_type == 'add': api_res = add_menu_api(params_add) - if operation_type == 'edit': + if modal_type == 'edit': api_res = edit_menu_api(params_edit) if api_res.get('code') == 200: - if operation_type == 'add': - return [ - None, - None, - None, - None, - None, - None, - None, - None, - False, - {'type': 'add'}, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('新增成功', type='success') - ] - if operation_type == 'edit': - return [ - None, - None, - None, - None, - None, - None, - None, - None, - False, - {'type': 'edit'}, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('编辑成功', type='success') - ] - - return [ - None, - None, - None, - None, - None, - None, - None, - None, - dash.no_update, - dash.no_update, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('处理失败', type='error') - ] - - return [ - None if parent_id else 'error', - None if menu_name else 'error', - None if order_num else 'error', - None if path else 'error', - None if parent_id else '请选择上级菜单!', - None if menu_name else '请输入菜单名称!', - None if order_num else '请输入显示排序!', - None if path else '请输入路由地址!', - dash.no_update, - dash.no_update, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('处理失败', type='error') - ] + if modal_type == 'add': + return dict( + form_validate=[None] * 8, + modal_visible=False, + operations={'type': 'add'}, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('新增成功', type='success') + ) + if modal_type == 'edit': + return dict( + form_validate=[None] * 8, + modal_visible=False, + operations={'type': 'edit'}, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('编辑成功', type='success') + ) + + return dict( + form_validate=[None] * 8, + modal_visible=dash.no_update, + operations=dash.no_update, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('处理失败', type='error') + ) + + return dict( + form_validate=[ + None if parent_id else 'error', + None if menu_name else 'error', + None if order_num else 'error', + None if path else 'error', + None if parent_id else '请选择上级菜单!', + None if menu_name else '请输入菜单名称!', + None if order_num else '请输入显示排序!', + None if path else '请输入路由地址!' + ], + modal_visible=dash.no_update, + operations=dash.no_update, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('处理失败', type='error') + ) - return [dash.no_update] * 12 + raise PreventUpdate @app.callback( @@ -130,6 +123,9 @@ def menu_confirm_menu(confirm_trigger, operation_type, cur_menu_info, parent_id, Input('menu-edit-id-store', 'data') ) def set_edit_info(edit_info): + """ + 菜单类型为菜单时回显菜单数据回调 + """ if edit_info: return [ edit_info.get('is_frame'), @@ -142,4 +138,4 @@ def set_edit_info(edit_info): edit_info.get('status') ] - return [dash.no_update] * 8 + raise PreventUpdate diff --git a/dash-fastapi-frontend/callbacks/system_c/menu_c/menu_c.py b/dash-fastapi-frontend/callbacks/system_c/menu_c/menu_c.py index de196db92fb53d4bcde5cbbf976f6c61b9376c8e..dfcdedd7c464005b753eb268fb866359596840c8 100644 --- a/dash-fastapi-frontend/callbacks/system_c/menu_c/menu_c.py +++ b/dash-fastapi-frontend/callbacks/system_c/menu_c/menu_c.py @@ -2,6 +2,7 @@ import dash import time import uuid from dash.dependencies import Input, Output, State, ALL +from dash.exceptions import PreventUpdate import feffery_antd_components as fac import feffery_utils_components as fuc @@ -12,22 +13,31 @@ from api.menu import get_menu_tree_api, get_menu_tree_for_edit_option_api, get_m @app.callback( - [Output('menu-list-table', 'data', allow_duplicate=True), - Output('menu-list-table', 'key'), - Output('menu-list-table', 'defaultExpandedRowKeys'), - Output('api-check-token', 'data', allow_duplicate=True), - Output('menu-fold', 'nClicks')], - [Input('menu-search', 'nClicks'), - Input('menu-refresh', 'nClicks'), - Input('menu-operations-store', 'data'), - Input('menu-fold', 'nClicks')], - [State('menu-menu_name-input', 'value'), - State('menu-status-select', 'value'), - State('menu-list-table', 'defaultExpandedRowKeys'), - State('menu-button-perms-container', 'data')], + output=dict( + menu_table_data=Output('menu-list-table', 'data', allow_duplicate=True), + menu_table_key=Output('menu-list-table', 'key'), + menu_table_defaultexpandedrowkeys=Output('menu-list-table', 'defaultExpandedRowKeys'), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True), + fold_click=Output('menu-fold', 'nClicks') + ), + inputs=dict( + search_click=Input('menu-search', 'nClicks'), + refresh_click=Input('menu-refresh', 'nClicks'), + operations=Input('menu-operations-store', 'data'), + fold_click=Input('menu-fold', 'nClicks') + ), + state=dict( + menu_name=State('menu-menu_name-input', 'value'), + status_select=State('menu-status-select', 'value'), + in_default_expanded_row_keys=State('menu-list-table', 'defaultExpandedRowKeys'), + button_perms=State('menu-button-perms-container', 'data') + ), prevent_initial_call=True ) def get_menu_table_data(search_click, refresh_click, operations, fold_click, menu_name, status_select, in_default_expanded_row_keys, button_perms): + """ + 获取菜单表格数据回调(进行表格相关增删查改操作后均会触发此回调) + """ query_params = dict( menu_name=menu_name, @@ -90,15 +100,40 @@ def get_menu_table_data(search_click, refresh_click, operations, fold_click, men if fold_click: if not in_default_expanded_row_keys: - return [table_data_new, str(uuid.uuid4()), default_expanded_row_keys, {'timestamp': time.time()}, None] - - return [table_data_new, str(uuid.uuid4()), [], {'timestamp': time.time()}, None] - - return [dash.no_update, dash.no_update, dash.no_update, {'timestamp': time.time()}, None] - - return [dash.no_update] * 4 + [None] + return dict( + menu_table_data=table_data_new, + menu_table_key=str(uuid.uuid4()), + menu_table_defaultexpandedrowkeys=default_expanded_row_keys, + api_check_token_trigger={'timestamp': time.time()}, + fold_click=None + ) + + return dict( + menu_table_data=table_data_new, + menu_table_key=str(uuid.uuid4()), + menu_table_defaultexpandedrowkeys=[], + api_check_token_trigger={'timestamp': time.time()}, + fold_click=None + ) + + return dict( + menu_table_data=dash.no_update, + menu_table_key=dash.no_update, + menu_table_defaultexpandedrowkeys=dash.no_update, + api_check_token_trigger={'timestamp': time.time()}, + fold_click=None + ) + + return dict( + menu_table_data=dash.no_update, + menu_table_key=dash.no_update, + menu_table_defaultexpandedrowkeys=dash.no_update, + api_check_token_trigger=dash.no_update, + fold_click=None + ) +# 重置菜单搜索表单数据回调 app.clientside_callback( ''' (reset_click) => { @@ -116,6 +151,7 @@ app.clientside_callback( ) +# 隐藏/显示菜单搜索表单回调 app.clientside_callback( ''' (hidden_click, hidden_status) => { @@ -143,36 +179,55 @@ app.clientside_callback( prevent_initial_call=True ) def get_select_icon(icon): + """ + 获取新增或编辑表单中选择的icon回调 + """ if icon: return [ icon, fac.AntdIcon(icon=icon) ] - return [dash.no_update] * 2 - + raise PreventUpdate @app.callback( - [Output('menu-modal', 'visible', allow_duplicate=True), - Output('menu-modal', 'title'), - Output('menu-parent_id', 'treeData'), - Output('menu-parent_id', 'value'), - Output('menu-menu_type', 'value'), - Output('menu-icon', 'value', allow_duplicate=True), - Output('menu-icon', 'prefix', allow_duplicate=True), - Output('menu-menu_name', 'value'), - Output('menu-order_num', 'value'), - Output('api-check-token', 'data', allow_duplicate=True), - Output('menu-edit-id-store', 'data'), - Output('menu-operations-store-bk', 'data')], - [Input({'type': 'menu-operation-button', 'index': ALL}, 'nClicks'), - Input('menu-list-table', 'nClicksButton')], - [State('menu-list-table', 'clickedContent'), - State('menu-list-table', 'recentlyButtonClickedRow')], + output=dict( + modal=dict(visible=Output('menu-modal', 'visible', allow_duplicate=True), title=Output('menu-modal', 'title')), + form_value=dict( + parent_tree=Output('menu-parent_id', 'treeData'), parent_id=Output('menu-parent_id', 'value'), + menu_type=Output('menu-menu_type', 'value'), icon=Output('menu-icon', 'value', allow_duplicate=True), + icon_prefix=Output('menu-icon', 'prefix', allow_duplicate=True), icon_category=Output('icon-category', 'value'), + menu_name=Output('menu-menu_name', 'value'), order_num=Output('menu-order_num', 'value') + ), + form_validate=[ + Output('menu-parent_id-form-item', 'validateStatus', allow_duplicate=True), + Output('menu-menu_name-form-item', 'validateStatus', allow_duplicate=True), + Output('menu-order_num-form-item', 'validateStatus', allow_duplicate=True), + Output('menu-parent_id-form-item', 'help', allow_duplicate=True), + Output('menu-menu_name-form-item', 'help', allow_duplicate=True), + Output('menu-order_num-form-item', 'help', allow_duplicate=True) + ], + other=dict( + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True), + edit_row_info=Output('menu-edit-id-store', 'data'), + modal_type=Output('menu-operations-store-bk', 'data') + ) + ), + inputs=dict( + operation_click=Input({'type': 'menu-operation-button', 'index': ALL}, 'nClicks'), + button_click=Input('menu-list-table', 'nClicksButton') + ), + state=dict( + clicked_content=State('menu-list-table', 'clickedContent'), + recently_button_clicked_row=State('menu-list-table', 'recentlyButtonClickedRow') + ), prevent_initial_call=True ) def add_edit_menu_modal(operation_click, button_click, clicked_content, recently_button_clicked_row): + """ + 显示新增或编辑菜单弹窗回调 + """ trigger_id = dash.ctx.triggered_id if trigger_id == {'index': 'add', 'type': 'menu-operation-button'} or (trigger_id == 'menu-list-table' and clicked_content != '删除'): menu_params = dict(menu_name='') @@ -184,58 +239,70 @@ def add_edit_menu_modal(operation_click, button_click, clicked_content, recently tree_data = tree_info['data'] if trigger_id == {'index': 'add', 'type': 'menu-operation-button'}: - return [ - True, - '新增菜单', - tree_data, - '0', - 'M', - None, - None, - None, - None, - {'timestamp': time.time()}, - None, - {'type': 'add'} - ] + return dict( + modal=dict(visible=True, title='新增菜单'), + form_value=dict( + parent_tree=tree_data, parent_id='0', menu_type='M', icon=None, + icon_prefix=None, icon_category=None, menu_name=None, order_num=None + ), + form_validate=[None] * 6, + other=dict( + api_check_token_trigger={'timestamp': time.time()}, + edit_row_info=None, + modal_type={'type': 'add'} + ) + ) elif trigger_id == 'menu-list-table' and clicked_content == '新增': - return [ - True, - '新增菜单', - tree_data, - str(recently_button_clicked_row['key']), - 'M', - None, - None, - None, - None, - {'timestamp': time.time()}, - None, - {'type': 'add'} - ] + return dict( + modal=dict(visible=True, title='新增菜单'), + form_value=dict( + parent_tree=tree_data, parent_id=str(recently_button_clicked_row['key']), menu_type='M', + icon=None, icon_prefix=None, icon_category=None, menu_name=None, order_num=None + ), + form_validate=[None] * 6, + other=dict( + api_check_token_trigger={'timestamp': time.time()}, + edit_row_info=None, + modal_type={'type': 'add'} + ) + ) elif trigger_id == 'menu-list-table' and clicked_content == '修改': menu_id = int(recently_button_clicked_row['key']) menu_info_res = get_menu_detail_api(menu_id=menu_id) if menu_info_res['code'] == 200: menu_info = menu_info_res['data'] - return [ - True, - '编辑菜单', - tree_data, - str(menu_info.get('parent_id')), - menu_info.get('menu_type'), - menu_info.get('icon'), - fac.AntdIcon(icon=menu_info.get('icon')), - menu_info.get('menu_name'), - menu_info.get('order_num'), - {'timestamp': time.time()}, - menu_info, - {'type': 'edit'} - ] - - return [dash.no_update] * 9 + [{'timestamp': time.time()}, None, None] - - return [dash.no_update] * 10 + [None, None] + return dict( + modal=dict(visible=True, title='编辑菜单'), + form_value=dict( + parent_tree=tree_data, parent_id=str(menu_info.get('parent_id')), + menu_type=menu_info.get('menu_type'), icon=menu_info.get('icon'), + icon_prefix=fac.AntdIcon(icon=menu_info.get('icon')), icon_category=menu_info.get('icon'), + menu_name=menu_info.get('menu_name'), order_num=menu_info.get('order_num') + ), + form_validate=[None] * 6, + other=dict( + api_check_token_trigger={'timestamp': time.time()}, + edit_row_info=menu_info, + modal_type={'type': 'edit'} + ) + ) + + return dict( + modal=dict(visible=dash.no_update, title=dash.no_update), + form_value=dict( + parent_tree=dash.no_update, parent_id=dash.no_update, menu_type=dash.no_update, + icon=dash.no_update, icon_prefix=dash.no_update, icon_category=dash.no_update, + menu_name=dash.no_update, order_num=dash.no_update + ), + form_validate=[dash.no_update] * 6, + other=dict( + api_check_token_trigger={'timestamp': time.time()}, + edit_row_info=None, + modal_type=None + ) + ) + + raise PreventUpdate @app.callback( @@ -258,7 +325,7 @@ def get_bottom_content(menu_value): elif menu_value == 'F': return [button_type.render(), str(uuid.uuid4()), {'type': 'F'}] - return dash.no_update + raise PreventUpdate @app.callback( @@ -293,7 +360,7 @@ def modal_confirm_trigger(confirm, menu_type): {'timestamp': time.time()} ] - return [dash.no_update] * 3 + raise PreventUpdate @app.callback( @@ -306,6 +373,9 @@ def modal_confirm_trigger(confirm, menu_type): prevent_initial_call=True ) def menu_delete_modal(button_click, clicked_content, recently_button_clicked_row): + """ + 显示删除菜单二次确认弹窗回调 + """ if button_click: if clicked_content == '删除': @@ -319,7 +389,7 @@ def menu_delete_modal(button_click, clicked_content, recently_button_clicked_row {'menu_ids': menu_ids} ] - return [dash.no_update] * 3 + raise PreventUpdate @app.callback( @@ -331,6 +401,9 @@ def menu_delete_modal(button_click, clicked_content, recently_button_clicked_row prevent_initial_call=True ) def menu_delete_confirm(delete_confirm, menu_ids_data): + """ + 删除菜单弹窗确认回调,实现删除操作 + """ if delete_confirm: params = menu_ids_data @@ -348,4 +421,4 @@ def menu_delete_confirm(delete_confirm, menu_ids_data): fuc.FefferyFancyMessage('删除失败', type='error') ] - return [dash.no_update] * 3 + raise PreventUpdate diff --git a/dash-fastapi-frontend/callbacks/system_c/notice_c.py b/dash-fastapi-frontend/callbacks/system_c/notice_c.py index 953deeb02c9ec67f75eb1c76911743c90c4e29a7..accdfd307c2fb8589f00f320f414439fc60c6518 100644 --- a/dash-fastapi-frontend/callbacks/system_c/notice_c.py +++ b/dash-fastapi-frontend/callbacks/system_c/notice_c.py @@ -5,6 +5,7 @@ import re import json from flask import session from dash.dependencies import Input, Output, State, ALL +from dash.exceptions import PreventUpdate import feffery_utils_components as fuc from server import app @@ -14,24 +15,33 @@ from api.dict import query_dict_data_list_api @app.callback( - [Output('notice-list-table', 'data', allow_duplicate=True), - Output('notice-list-table', 'pagination', allow_duplicate=True), - Output('notice-list-table', 'key'), - Output('notice-list-table', 'selectedRowKeys'), - Output('api-check-token', 'data', allow_duplicate=True)], - [Input('notice-search', 'nClicks'), - Input('notice-refresh', 'nClicks'), - Input('notice-list-table', 'pagination'), - Input('notice-operations-store', 'data')], - [State('notice-notice_title-input', 'value'), - State('notice-update_by-input', 'value'), - State('notice-notice_type-select', 'value'), - State('notice-create_time-range', 'value'), - State('notice-button-perms-container', 'data')], + output=dict( + notice_table_data=Output('notice-list-table', 'data', allow_duplicate=True), + notice_table_pagination=Output('notice-list-table', 'pagination', allow_duplicate=True), + notice_table_key=Output('notice-list-table', 'key'), + notice_table_selectedrowkeys=Output('notice-list-table', 'selectedRowKeys'), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True) + ), + inputs=dict( + search_click=Input('notice-search', 'nClicks'), + refresh_click=Input('notice-refresh', 'nClicks'), + pagination=Input('notice-list-table', 'pagination'), + operations=Input('notice-operations-store', 'data') + ), + state=dict( + notice_title=State('notice-notice_title-input', 'value'), + update_by=State('notice-update_by-input', 'value'), + notice_type=State('notice-notice_type-select', 'value'), + create_time_range=State('notice-create_time-range', 'value'), + button_perms=State('notice-button-perms-container', 'data') + ), prevent_initial_call=True ) def get_notice_table_data(search_click, refresh_click, pagination, operations, notice_title, update_by, notice_type, create_time_range, button_perms): + """ + 获取通知公告表格数据回调(进行表格相关增删查改操作后均会触发此回调) + """ create_time_start = None create_time_end = None if create_time_range: @@ -102,13 +112,26 @@ def get_notice_table_data(search_click, refresh_click, pagination, operations, n } if 'system:notice:remove' in button_perms else {}, ] - return [table_data, table_pagination, str(uuid.uuid4()), None, {'timestamp': time.time()}] + return dict( + notice_table_data=table_data, + notice_table_pagination=table_pagination, + notice_table_key=str(uuid.uuid4()), + notice_table_selectedrowkeys=None, + api_check_token_trigger={'timestamp': time.time()} + ) - return [dash.no_update, dash.no_update, dash.no_update, dash.no_update, {'timestamp': time.time()}] + return dict( + notice_table_data=dash.no_update, + notice_table_pagination=dash.no_update, + notice_table_key=dash.no_update, + notice_table_selectedrowkeys=dash.no_update, + api_check_token_trigger={'timestamp': time.time()} + ) - return [dash.no_update] * 5 + raise PreventUpdate +# 重置通知公告搜索表单数据回调 app.clientside_callback( ''' (reset_click) => { @@ -128,6 +151,7 @@ app.clientside_callback( ) +# 隐藏/显示通知公告搜索表单回调 app.clientside_callback( ''' (hidden_click, hidden_status) => { @@ -154,6 +178,9 @@ app.clientside_callback( prevent_initial_call=True ) def change_notice_edit_button_status(table_rows_selected): + """ + 根据选择的表格数据行数控制编辑按钮状态回调 + """ outputs_list = dash.ctx.outputs_list if outputs_list: if table_rows_selected: @@ -164,7 +191,7 @@ def change_notice_edit_button_status(table_rows_selected): return True - return dash.no_update + raise PreventUpdate @app.callback( @@ -173,17 +200,18 @@ def change_notice_edit_button_status(table_rows_selected): prevent_initial_call=True ) def change_notice_delete_button_status(table_rows_selected): + """ + 根据选择的表格数据行数控制删除按钮状态回调 + """ outputs_list = dash.ctx.outputs_list if outputs_list: if table_rows_selected: - if len(table_rows_selected) > 1: - return False return False return True - return dash.no_update + raise PreventUpdate @app.callback( @@ -192,6 +220,9 @@ def change_notice_delete_button_status(table_rows_selected): prevent_initial_call=True ) def init_render_editor(html_string): + """ + 初始化富文本编辑器回调 + """ url = f'{ApiBaseUrlConfig.BaseUrl}/common/uploadForEditor' token = 'Bearer ' + session.get('Authorization') @@ -286,40 +317,57 @@ def init_render_editor(html_string): @app.callback( - [Output('notice-modal', 'visible', allow_duplicate=True), - Output('notice-modal', 'title'), - Output('notice-notice_title', 'value'), - Output('notice-notice_type', 'value'), - Output('notice-status', 'value'), - Output('notice-written-editor-store', 'data'), - Output('api-check-token', 'data', allow_duplicate=True), - Output('notice-edit-id-store', 'data'), - Output('notice-operations-store-bk', 'data')], - [Input({'type': 'notice-operation-button', 'index': ALL}, 'nClicks'), - Input('notice-list-table', 'nClicksButton')], - [State('notice-list-table', 'selectedRowKeys'), - State('notice-list-table', 'clickedContent'), - State('notice-list-table', 'recentlyButtonClickedRow')], + output=dict( + modal=dict(visible=Output('notice-modal', 'visible', allow_duplicate=True), title=Output('notice-modal', 'title')), + form_value=dict( + notice_title=Output('notice-notice_title', 'value'), + notice_type=Output('notice-notice_type', 'value'), + status=Output('notice-status', 'value'), + editor_content=Output('notice-written-editor-store', 'data'), + ), + form_validate=[ + Output('notice-notice_title-form-item', 'validateStatus', allow_duplicate=True), + Output('notice-notice_type-form-item', 'validateStatus', allow_duplicate=True), + Output('notice-notice_title-form-item', 'help', allow_duplicate=True), + Output('notice-notice_type-form-item', 'help', allow_duplicate=True) + ], + other=dict( + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True), + edit_row_info=Output('notice-edit-id-store', 'data'), + modal_type=Output('notice-operations-store-bk', 'data') + ) + ), + inputs=dict( + operation_click=Input({'type': 'notice-operation-button', 'index': ALL}, 'nClicks'), + button_click=Input('notice-list-table', 'nClicksButton') + ), + state=dict( + selected_row_keys=State('notice-list-table', 'selectedRowKeys'), + clicked_content=State('notice-list-table', 'clickedContent'), + recently_button_clicked_row=State('notice-list-table', 'recentlyButtonClickedRow') + ), prevent_initial_call=True ) def add_edit_notice_modal(operation_click, button_click, selected_row_keys, clicked_content, recently_button_clicked_row): + """ + 显示新增或编辑通知公告弹窗回调 + """ trigger_id = dash.ctx.triggered_id if trigger_id == {'index': 'add', 'type': 'notice-operation-button'} \ or trigger_id == {'index': 'edit', 'type': 'notice-operation-button'} \ or (trigger_id == 'notice-list-table' and clicked_content == '修改'): if trigger_id == {'index': 'add', 'type': 'notice-operation-button'}: - return [ - True, - '新增通知公告', - None, - None, - '0', - '


', - dash.no_update, - None, - {'type': 'add'} - ] + return dict( + modal=dict(visible=True, title='新增通知公告'), + form_value=dict(notice_title=None, notice_type=None, status='0', editor_content='


'), + form_validate=[None] * 4, + other=dict( + api_check_token_trigger=dash.no_update, + edit_row_info=None, + modal_type={'type': 'add'} + ) + ) elif trigger_id == {'index': 'edit', 'type': 'notice-operation-button'} or (trigger_id == 'notice-list-table' and clicked_content == '修改'): if trigger_id == {'index': 'edit', 'type': 'notice-operation-button'}: notice_id = int(','.join(selected_row_keys)) @@ -330,102 +378,129 @@ def add_edit_notice_modal(operation_click, button_click, selected_row_keys, clic notice_info = notice_info_res['data'] notice_content = notice_info.get('notice_content') - return [ - True, - '编辑通知公告', - notice_info.get('notice_title'), - notice_info.get('notice_type'), - notice_info.get('status'), - re.sub(r"\n", "", notice_content), - {'timestamp': time.time()}, - notice_info if notice_info else None, - {'type': 'edit'} - ] + return dict( + modal=dict(visible=True, title='编辑通知公告'), + form_value=dict( + notice_title=notice_info.get('notice_title'), + notice_type=notice_info.get('notice_type'), + status=notice_info.get('status'), + editor_content=re.sub(r"\n", "", notice_content) + ), + form_validate=[None] * 4, + other=dict( + api_check_token_trigger={'timestamp': time.time()}, + edit_row_info=notice_info if notice_info else None, + modal_type={'type': 'edit'} + ) + ) - return [dash.no_update] * 6 + [{'timestamp': time.time()}, None, None] + return dict( + modal=dict(visible=dash.no_update, title=dash.no_update), + form_value=dict( + notice_title=dash.no_update, + notice_type=dash.no_update, + status=dash.no_update, + editor_content=dash.no_update + ), + form_validate=[dash.no_update] * 4, + other=dict( + api_check_token_trigger={'timestamp': time.time()}, + edit_row_info=None, + modal_type=None + ) + ) - return [dash.no_update] * 7 + [None, None] + raise PreventUpdate @app.callback( - [Output('notice-notice_title-form-item', 'validateStatus'), - Output('notice-notice_type-form-item', 'validateStatus'), - Output('notice-notice_title-form-item', 'help'), - Output('notice-notice_type-form-item', 'help'), - Output('notice-modal', 'visible'), - Output('notice-operations-store', 'data', allow_duplicate=True), - Output('api-check-token', 'data', allow_duplicate=True), - Output('global-message-container', 'children', allow_duplicate=True)], - Input('notice-modal', 'okCounts'), - [State('notice-operations-store-bk', 'data'), - State('notice-edit-id-store', 'data'), - State('notice-notice_title', 'value'), - State('notice-notice_type', 'value'), - State('notice-status', 'value'), - State('notice-content', 'data')], + output=dict( + notice_title_form_status=Output('notice-notice_title-form-item', 'validateStatus', allow_duplicate=True), + notice_type_form_status=Output('notice-notice_type-form-item', 'validateStatus', allow_duplicate=True), + notice_title_form_help=Output('notice-notice_title-form-item', 'help', allow_duplicate=True), + notice_type_form_help=Output('notice-notice_type-form-item', 'help', allow_duplicate=True), + modal_visible=Output('notice-modal', 'visible'), + operations=Output('notice-operations-store', 'data', allow_duplicate=True), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True), + global_message_container=Output('global-message-container', 'children', allow_duplicate=True) + ), + inputs=dict( + confirm_trigger=Input('notice-modal', 'okCounts') + ), + state=dict( + modal_type=State('notice-operations-store-bk', 'data'), + edit_row_info=State('notice-edit-id-store', 'data'), + notice_title=State('notice-notice_title', 'value'), + notice_type=State('notice-notice_type', 'value'), + status=State('notice-status', 'value'), + notice_content=State('notice-content', 'data') + ), prevent_initial_call=True ) -def notice_confirm(confirm_trigger, operation_type, cur_notice_info, notice_title, notice_type, status, notice_content): +def notice_confirm(confirm_trigger, modal_type, edit_row_info, notice_title, notice_type, status, notice_content): + """ + 新增或编辑通知公告弹窗确认回调,实现新增或编辑操作 + """ if confirm_trigger: if all([notice_title, notice_type]): params_add = dict(notice_title=notice_title, notice_type=notice_type, status=status, notice_content=notice_content.get('html')) - params_edit = dict(notice_id=cur_notice_info.get('notice_id') if cur_notice_info else None, + params_edit = dict(notice_id=edit_row_info.get('notice_id') if edit_row_info else None, notice_title=notice_title, notice_type=notice_type, status=status, notice_content=notice_content.get('html')) api_res = {} - operation_type = operation_type.get('type') - if operation_type == 'add': + modal_type = modal_type.get('type') + if modal_type == 'add': api_res = add_notice_api(params_add) - if operation_type == 'edit': + if modal_type == 'edit': api_res = edit_notice_api(params_edit) if api_res.get('code') == 200: - if operation_type == 'add': - return [ - None, - None, - None, - None, - False, - {'type': 'add'}, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('新增成功', type='success') - ] - if operation_type == 'edit': - return [ - None, - None, - None, - None, - False, - {'type': 'edit'}, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('编辑成功', type='success') - ] - - return [ - None, - None, - None, - None, - dash.no_update, - dash.no_update, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('处理失败', type='error') - ] + if modal_type == 'add': + return dict( + notice_title_form_status=None, + notice_type_form_status=None, + notice_title_form_help=None, + notice_type_form_help=None, + modal_visible=False, + operations={'type': 'add'}, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('新增成功', type='success') + ) + if modal_type == 'edit': + return dict( + notice_title_form_status=None, + notice_type_form_status=None, + notice_title_form_help=None, + notice_type_form_help=None, + modal_visible=False, + operations={'type': 'edit'}, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('编辑成功', type='success') + ) + + return dict( + notice_title_form_status=None, + notice_type_form_status=None, + notice_title_form_help=None, + notice_type_form_help=None, + modal_visible=dash.no_update, + operations=dash.no_update, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('处理失败', type='error') + ) - return [ - None if notice_title else 'error', - None if notice_type else 'error', - None if notice_title else '请输入公告标题!', - None if notice_type else '请输入公告类型!', - dash.no_update, - dash.no_update, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('处理失败', type='error') - ] + return dict( + notice_title_form_status=None if notice_title else 'error', + notice_type_form_status=None if notice_type else 'error', + notice_title_form_help=None if notice_title else '请输入公告标题!', + notice_type_form_help=None if notice_type else '请输入公告类型!', + modal_visible=dash.no_update, + operations=dash.no_update, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('处理失败', type='error') + ) - return [dash.no_update] * 8 + raise PreventUpdate @app.callback( @@ -441,6 +516,9 @@ def notice_confirm(confirm_trigger, operation_type, cur_notice_info, notice_titl ) def notice_delete_modal(operation_click, button_click, selected_row_keys, clicked_content, recently_button_clicked_row): + """ + 显示删除通知公告二次确认弹窗回调 + """ trigger_id = dash.ctx.triggered_id if trigger_id == {'index': 'delete', 'type': 'notice-operation-button'} or ( trigger_id == 'notice-list-table' and clicked_content == '删除'): @@ -460,7 +538,7 @@ def notice_delete_modal(operation_click, button_click, {'notice_ids': notice_ids} ] - return [dash.no_update] * 3 + raise PreventUpdate @app.callback( @@ -472,6 +550,9 @@ def notice_delete_modal(operation_click, button_click, prevent_initial_call=True ) def notice_delete_confirm(delete_confirm, notice_ids_data): + """ + 删除岗通知公告弹窗确认回调,实现删除操作 + """ if delete_confirm: params = notice_ids_data @@ -489,4 +570,4 @@ def notice_delete_confirm(delete_confirm, notice_ids_data): fuc.FefferyFancyMessage('删除失败', type='error') ] - return [dash.no_update] * 3 + raise PreventUpdate diff --git a/dash-fastapi-frontend/callbacks/system_c/post_c.py b/dash-fastapi-frontend/callbacks/system_c/post_c.py index 30c46dc28190d80bea6bb8fff2c7e60d79b83b4e..1f8985a4710a2765ff8878dbfe4aa4f78363a100 100644 --- a/dash-fastapi-frontend/callbacks/system_c/post_c.py +++ b/dash-fastapi-frontend/callbacks/system_c/post_c.py @@ -3,6 +3,7 @@ import time import uuid from dash import dcc from dash.dependencies import Input, Output, State, ALL +from dash.exceptions import PreventUpdate import feffery_utils_components as fuc from server import app @@ -10,22 +11,31 @@ from api.post import get_post_list_api, get_post_detail_api, add_post_api, edit_ @app.callback( - [Output('post-list-table', 'data', allow_duplicate=True), - Output('post-list-table', 'pagination', allow_duplicate=True), - Output('post-list-table', 'key'), - Output('post-list-table', 'selectedRowKeys'), - Output('api-check-token', 'data', allow_duplicate=True)], - [Input('post-search', 'nClicks'), - Input('post-refresh', 'nClicks'), - Input('post-list-table', 'pagination'), - Input('post-operations-store', 'data')], - [State('post-post_code-input', 'value'), - State('post-post_name-input', 'value'), - State('post-status-select', 'value'), - State('post-button-perms-container', 'data')], + output=dict( + post_table_data=Output('post-list-table', 'data', allow_duplicate=True), + post_table_pagination=Output('post-list-table', 'pagination', allow_duplicate=True), + post_table_key=Output('post-list-table', 'key'), + post_table_selectedrowkeys=Output('post-list-table', 'selectedRowKeys'), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True) + ), + inputs=dict( + search_click=Input('post-search', 'nClicks'), + refresh_click=Input('post-refresh', 'nClicks'), + pagination=Input('post-list-table', 'pagination'), + operations=Input('post-operations-store', 'data') + ), + state=dict( + post_code=State('post-post_code-input', 'value'), + post_name=State('post-post_name-input', 'value'), + status_select=State('post-status-select', 'value'), + button_perms=State('post-button-perms-container', 'data') + ), prevent_initial_call=True ) def get_post_table_data(search_click, refresh_click, pagination, operations, post_code, post_name, status_select, button_perms): + """ + 获取岗位表格数据回调(进行表格相关增删查改操作后均会触发此回调) + """ query_params = dict( post_code=post_code, @@ -73,14 +83,26 @@ def get_post_table_data(search_click, refresh_click, pagination, operations, pos 'icon': 'antd-delete' } if 'system:post:remove' in button_perms else {}, ] + return dict( + post_table_data=table_data, + post_table_pagination=table_pagination, + post_table_key=str(uuid.uuid4()), + post_table_selectedrowkeys=None, + api_check_token_trigger={'timestamp': time.time()} + ) - return [table_data, table_pagination, str(uuid.uuid4()), None, {'timestamp': time.time()}] - - return [dash.no_update, dash.no_update, dash.no_update, dash.no_update, {'timestamp': time.time()}] + return dict( + post_table_data=dash.no_update, + post_table_pagination=dash.no_update, + post_table_key=dash.no_update, + post_table_selectedrowkeys=dash.no_update, + api_check_token_trigger={'timestamp': time.time()} + ) - return [dash.no_update] * 5 + raise PreventUpdate +# 重置岗位搜索表单数据回调 app.clientside_callback( ''' (reset_click) => { @@ -99,6 +121,7 @@ app.clientside_callback( ) +# 隐藏/显示岗位搜索表单回调 app.clientside_callback( ''' (hidden_click, hidden_status) => { @@ -125,6 +148,9 @@ app.clientside_callback( prevent_initial_call=True ) def change_post_edit_button_status(table_rows_selected): + """ + 根据选择的表格数据行数控制编辑按钮状态回调 + """ outputs_list = dash.ctx.outputs_list if outputs_list: if table_rows_selected: @@ -135,7 +161,7 @@ def change_post_edit_button_status(table_rows_selected): return True - return dash.no_update + raise PreventUpdate @app.callback( @@ -144,55 +170,66 @@ def change_post_edit_button_status(table_rows_selected): prevent_initial_call=True ) def change_post_delete_button_status(table_rows_selected): + """ + 根据选择的表格数据行数控制删除按钮状态回调 + """ outputs_list = dash.ctx.outputs_list if outputs_list: if table_rows_selected: - if len(table_rows_selected) > 1: - return False return False return True - return dash.no_update + raise PreventUpdate @app.callback( - [Output('post-modal', 'visible', allow_duplicate=True), - Output('post-modal', 'title'), - Output('post-post_name', 'value'), - Output('post-post_code', 'value'), - Output('post-post_sort', 'value'), - Output('post-status', 'value'), - Output('post-remark', 'value'), - Output('api-check-token', 'data', allow_duplicate=True), - Output('post-edit-id-store', 'data'), - Output('post-operations-store-bk', 'data')], - [Input({'type': 'post-operation-button', 'index': ALL}, 'nClicks'), - Input('post-list-table', 'nClicksButton')], - [State('post-list-table', 'selectedRowKeys'), - State('post-list-table', 'clickedContent'), - State('post-list-table', 'recentlyButtonClickedRow')], + output=dict( + modal_visible=Output('post-modal', 'visible', allow_duplicate=True), + modal_title=Output('post-modal', 'title'), + form_value=Output({'type': 'post-form-value', 'index': ALL}, 'value'), + form_label_validate_status=Output({'type': 'post-form-label', 'index': ALL, 'required': True}, 'validateStatus', allow_duplicate=True), + form_label_validate_info=Output({'type': 'post-form-label', 'index': ALL, 'required': True}, 'help', allow_duplicate=True), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True), + edit_row_info=Output('post-edit-id-store', 'data'), + modal_type=Output('post-operations-store-bk', 'data') + ), + inputs=dict( + operation_click=Input({'type': 'post-operation-button', 'index': ALL}, 'nClicks'), + button_click=Input('post-list-table', 'nClicksButton') + ), + state=dict( + selected_row_keys=State('post-list-table', 'selectedRowKeys'), + clicked_content=State('post-list-table', 'clickedContent'), + recently_button_clicked_row=State('post-list-table', 'recentlyButtonClickedRow') + ), prevent_initial_call=True ) def add_edit_post_modal(operation_click, button_click, selected_row_keys, clicked_content, recently_button_clicked_row): + """ + 显示新增或编辑岗位弹窗回调 + """ trigger_id = dash.ctx.triggered_id if trigger_id == {'index': 'add', 'type': 'post-operation-button'} \ or trigger_id == {'index': 'edit', 'type': 'post-operation-button'} \ or (trigger_id == 'post-list-table' and clicked_content == '修改'): + # 获取所有输出表单项对应value的index + form_value_list = [x['id']['index'] for x in dash.ctx.outputs_list[2]] + # 获取所有输出表单项对应label的index + form_label_list = [x['id']['index'] for x in dash.ctx.outputs_list[3]] if trigger_id == {'index': 'add', 'type': 'post-operation-button'}: - return [ - True, - '新增岗位', - None, - None, - 0, - '0', - None, - dash.no_update, - None, - {'type': 'add'} - ] + post_info = dict(post_name=None, post_code=None, post_sort=0, status='0', remark=None) + return dict( + modal_visible=True, + modal_title='新增岗位', + form_value=[post_info.get(k) for k in form_value_list], + form_label_validate_status=[None] * len(form_label_list), + form_label_validate_info=[None] * len(form_label_list), + api_check_token_trigger=dash.no_update, + edit_row_info=None, + modal_type={'type': 'add'} + ) elif trigger_id == {'index': 'edit', 'type': 'post-operation-button'} or (trigger_id == 'post-list-table' and clicked_content == '修改'): if trigger_id == {'index': 'edit', 'type': 'post-operation-button'}: post_id = int(','.join(selected_row_keys)) @@ -201,112 +238,112 @@ def add_edit_post_modal(operation_click, button_click, selected_row_keys, clicke post_info_res = get_post_detail_api(post_id=post_id) if post_info_res['code'] == 200: post_info = post_info_res['data'] - return [ - True, - '编辑岗位', - post_info.get('post_name'), - post_info.get('post_code'), - post_info.get('post_sort'), - post_info.get('status'), - post_info.get('remark'), - {'timestamp': time.time()}, - post_info if post_info else None, - {'type': 'edit'} - ] - - return [dash.no_update] * 7 + [{'timestamp': time.time()}, None, None] + return dict( + modal_visible=True, + modal_title='编辑岗位', + form_value=[post_info.get(k) for k in form_value_list], + form_label_validate_status=[None] * len(form_label_list), + form_label_validate_info=[None] * len(form_label_list), + api_check_token_trigger={'timestamp': time.time()}, + edit_row_info=post_info if post_info else None, + modal_type={'type': 'edit'} + ) + + return dict( + modal_visible=dash.no_update, + modal_title=dash.no_update, + form_value=[dash.no_update] * len(form_value_list), + form_label_validate_status=[dash.no_update] * len(form_label_list), + form_label_validate_info=[dash.no_update] * len(form_label_list), + api_check_token_trigger={'timestamp': time.time()}, + edit_row_info=None, + modal_type=None + ) - return [dash.no_update] * 8 + [None, None] + raise PreventUpdate @app.callback( - [Output('post-post_name-form-item', 'validateStatus'), - Output('post-post_code-form-item', 'validateStatus'), - Output('post-post_sort-form-item', 'validateStatus'), - Output('post-post_name-form-item', 'help'), - Output('post-post_code-form-item', 'help'), - Output('post-post_sort-form-item', 'help'), - Output('post-modal', 'visible'), - Output('post-operations-store', 'data', allow_duplicate=True), - Output('api-check-token', 'data', allow_duplicate=True), - Output('global-message-container', 'children', allow_duplicate=True)], - Input('post-modal', 'okCounts'), - [State('post-operations-store-bk', 'data'), - State('post-edit-id-store', 'data'), - State('post-post_name', 'value'), - State('post-post_code', 'value'), - State('post-post_sort', 'value'), - State('post-status', 'value'), - State('post-remark', 'value')], + output=dict( + form_label_validate_status=Output({'type': 'post-form-label', 'index': ALL, 'required': True}, 'validateStatus', + allow_duplicate=True), + form_label_validate_info=Output({'type': 'post-form-label', 'index': ALL, 'required': True}, 'help', + allow_duplicate=True), + modal_visible=Output('post-modal', 'visible'), + operations=Output('post-operations-store', 'data', allow_duplicate=True), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True), + global_message_container=Output('global-message-container', 'children', allow_duplicate=True) + ), + inputs=dict( + confirm_trigger=Input('post-modal', 'okCounts') + ), + state=dict( + modal_type=State('post-operations-store-bk', 'data'), + edit_row_info=State('post-edit-id-store', 'data'), + form_value=State({'type': 'post-form-value', 'index': ALL}, 'value'), + form_label=State({'type': 'post-form-label', 'index': ALL, 'required': True}, 'label') + ), prevent_initial_call=True ) -def post_confirm(confirm_trigger, operation_type, cur_post_info, post_name, post_code, post_sort, status, remark): +def post_confirm(confirm_trigger, modal_type, edit_row_info, form_value, form_label): + """ + 新增或编辑岗位弹窗确认回调,实现新增或编辑操作 + """ if confirm_trigger: - if all([post_name, post_code, post_sort]): - params_add = dict(post_name=post_name, post_code=post_code, post_sort=post_sort, status=status, remark=remark) - params_edit = dict(post_id=cur_post_info.get('post_id') if cur_post_info else None, post_name=post_name, - post_code=post_code, post_sort=post_sort, status=status, remark=remark) + # 获取所有输出表单项对应label的index + form_label_output_list = [x['id']['index'] for x in dash.ctx.outputs_list[0]] + # 获取所有输入表单项对应的value及label + form_value_state = {x['id']['index']: x.get('value') for x in dash.ctx.states_list[-2]} + form_label_state = {x['id']['index']: x.get('value') for x in dash.ctx.states_list[-1]} + if all([form_value_state.get(k) for k in form_label_output_list]): + params_add = form_value_state + params_edit = params_add.copy() + params_edit['post_id'] = edit_row_info.get('post_id') if edit_row_info else None api_res = {} - operation_type = operation_type.get('type') - if operation_type == 'add': + modal_type = modal_type.get('type') + if modal_type == 'add': api_res = add_post_api(params_add) - if operation_type == 'edit': + if modal_type == 'edit': api_res = edit_post_api(params_edit) if api_res.get('code') == 200: - if operation_type == 'add': - return [ - None, - None, - None, - None, - None, - None, - False, - {'type': 'add'}, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('新增成功', type='success') - ] - if operation_type == 'edit': - return [ - None, - None, - None, - None, - None, - None, - False, - {'type': 'edit'}, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('编辑成功', type='success') - ] - - return [ - None, - None, - None, - None, - None, - None, - dash.no_update, - dash.no_update, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('处理失败', type='error') - ] - - return [ - None if post_name else 'error', - None if post_code else 'error', - None if post_sort else 'error', - None if post_name else '请输入岗位名称!', - None if post_code else '请输入岗位编码!', - None if post_sort else '请输入岗位顺序!', - dash.no_update, - dash.no_update, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('处理失败', type='error') - ] + if modal_type == 'add': + return dict( + form_label_validate_status=[None] * len(form_label_output_list), + form_label_validate_info=[None] * len(form_label_output_list), + modal_visible=False, + operations={'type': 'add'}, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('新增成功', type='success') + ) + if modal_type == 'edit': + return dict( + form_label_validate_status=[None] * len(form_label_output_list), + form_label_validate_info=[None] * len(form_label_output_list), + modal_visible=False, + operations={'type': 'edit'}, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('编辑成功', type='success') + ) + + return dict( + form_label_validate_status=[None] * len(form_label_output_list), + form_label_validate_info=[None] * len(form_label_output_list), + modal_visible=dash.no_update, + operations=dash.no_update, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('处理失败', type='error') + ) + + return dict( + form_label_validate_status=[None if form_value_state.get(k) else 'error' for k in form_label_output_list], + form_label_validate_info=[None if form_value_state.get(k) else f'{form_label_state.get(k)}不能为空!' for k in form_label_output_list], + modal_visible=dash.no_update, + operations=dash.no_update, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('处理失败', type='error') + ) - return [dash.no_update] * 10 + raise PreventUpdate @app.callback( @@ -322,6 +359,9 @@ def post_confirm(confirm_trigger, operation_type, cur_post_info, post_name, post ) def post_delete_modal(operation_click, button_click, selected_row_keys, clicked_content, recently_button_clicked_row): + """ + 显示删除岗位二次确认弹窗回调 + """ trigger_id = dash.ctx.triggered_id if trigger_id == {'index': 'delete', 'type': 'post-operation-button'} or (trigger_id == 'post-list-table' and clicked_content == '删除'): @@ -331,7 +371,7 @@ def post_delete_modal(operation_click, button_click, if clicked_content == '删除': post_ids = recently_button_clicked_row['key'] else: - return dash.no_update + raise PreventUpdate return [ f'是否确认删除岗位编号为{post_ids}的岗位?', @@ -339,7 +379,7 @@ def post_delete_modal(operation_click, button_click, {'post_ids': post_ids} ] - return [dash.no_update] * 3 + raise PreventUpdate @app.callback( @@ -351,6 +391,9 @@ def post_delete_modal(operation_click, button_click, prevent_initial_call=True ) def post_delete_confirm(delete_confirm, post_ids_data): + """ + 删除岗位弹窗确认回调,实现删除操作 + """ if delete_confirm: params = post_ids_data @@ -368,7 +411,7 @@ def post_delete_confirm(delete_confirm, post_ids_data): fuc.FefferyFancyMessage('删除失败', type='error') ] - return [dash.no_update] * 3 + raise PreventUpdate @app.callback( @@ -380,6 +423,9 @@ def post_delete_confirm(delete_confirm, post_ids_data): prevent_initial_call=True ) def export_post_list(export_click): + """ + 导出岗位信息回调 + """ if export_click: export_post_res = export_post_list_api({}) if export_post_res.status_code == 200: @@ -399,7 +445,7 @@ def export_post_list(export_click): fuc.FefferyFancyMessage('导出失败', type='error') ] - return [dash.no_update] * 4 + raise PreventUpdate @app.callback( @@ -408,9 +454,12 @@ def export_post_list(export_click): prevent_initial_call=True ) def reset_post_export_status(data): + """ + 导出完成后重置下载组件数据回调,防止重复下载文件 + """ time.sleep(0.5) if data: return None - return dash.no_update + raise PreventUpdate diff --git a/dash-fastapi-frontend/callbacks/system_c/role_c/allocate_user_c.py b/dash-fastapi-frontend/callbacks/system_c/role_c/allocate_user_c.py index 326839503d3778dea9dcf3ed8fab1b0f5901e5d7..9c3a9255fa031ad18056414e7c6e50d2d8120111 100644 --- a/dash-fastapi-frontend/callbacks/system_c/role_c/allocate_user_c.py +++ b/dash-fastapi-frontend/callbacks/system_c/role_c/allocate_user_c.py @@ -2,6 +2,7 @@ import dash import time import uuid from dash.dependencies import Input, Output, State, ALL, MATCH +from dash.exceptions import PreventUpdate import feffery_utils_components as fuc from server import app @@ -24,6 +25,9 @@ from api.role import get_allocated_user_list_api, get_unallocated_user_list_api, prevent_initial_call=True ) def get_allocate_user_table_data(search_click, refresh_click, pagination, operations, user_name, phonenumber, role_id, button_perms): + """ + 使用模式匹配回调MATCH模式,根据不同类型获取角色已分配用户列表及未分配用户列表(进行表格相关增删查改操作后均会触发此回调) + """ query_params = dict( role_id=int(role_id), @@ -76,9 +80,10 @@ def get_allocate_user_table_data(search_click, refresh_click, pagination, operat return [dash.no_update, dash.no_update, dash.no_update, dash.no_update] - return [dash.no_update] * 4 + raise PreventUpdate +# 重置分配用户搜索表单数据回调 app.clientside_callback( ''' (reset_click) => { @@ -96,6 +101,7 @@ app.clientside_callback( ) +# 隐藏/显示分配用户搜索表单回调 app.clientside_callback( ''' (hidden_click, hidden_status) => { @@ -122,6 +128,9 @@ app.clientside_callback( prevent_initial_call=True ) def change_allocated_user_delete_button_status(table_rows_selected): + """ + 根据选择的表格数据行数控制取批量消授权按钮状态回调 + """ outputs_list = dash.ctx.outputs_list if outputs_list: if table_rows_selected: @@ -129,7 +138,7 @@ def change_allocated_user_delete_button_status(table_rows_selected): return True - return dash.no_update + raise PreventUpdate @app.callback( @@ -140,11 +149,14 @@ def change_allocated_user_delete_button_status(table_rows_selected): prevent_initial_call=True ) def allocate_user_modal(add_click, unallocated_user): + """ + 分配用户弹框中添加用户按钮回调 + """ if add_click: return [True, unallocated_user + 1 if unallocated_user else 1] - return [dash.no_update] * 2 + raise PreventUpdate @app.callback( @@ -158,6 +170,9 @@ def allocate_user_modal(add_click, unallocated_user): prevent_initial_call=True ) def allocate_user_add_confirm(add_confirm, selected_row_keys, role_id): + """ + 添加用户确认回调,实现给角色分配用户操作 + """ if add_confirm: if selected_row_keys: @@ -185,7 +200,7 @@ def allocate_user_add_confirm(add_confirm, selected_row_keys, role_id): fuc.FefferyFancyMessage('请选择用户', type='error') ] - return [dash.no_update] * 4 + raise PreventUpdate @app.callback( @@ -201,6 +216,9 @@ def allocate_user_add_confirm(add_confirm, selected_row_keys, role_id): ) def allocate_user_delete_modal(operation_click, button_click, selected_row_keys, clicked_content, recently_button_clicked_row): + """ + 显示取消授权二次确认弹窗回调 + """ trigger_id = dash.ctx.triggered_id if trigger_id.type == 'allocate_user-operation-button' or ( trigger_id.type == 'allocate_user-list-table' and clicked_content == '取消授权'): @@ -219,7 +237,7 @@ def allocate_user_delete_modal(operation_click, button_click, user_ids ] - return [dash.no_update] * 3 + raise PreventUpdate @app.callback( @@ -232,6 +250,9 @@ def allocate_user_delete_modal(operation_click, button_click, prevent_initial_call=True ) def allocate_user_delete_confirm(delete_confirm, user_ids_data, role_id): + """ + 取消授权弹窗确认回调,实现取消授权操作 + """ if delete_confirm: params = {'user_ids': user_ids_data, 'role_ids': role_id} @@ -249,4 +270,4 @@ def allocate_user_delete_confirm(delete_confirm, user_ids_data, role_id): fuc.FefferyFancyMessage('取消授权失败', type='error') ] - return [dash.no_update] * 3 + raise PreventUpdate diff --git a/dash-fastapi-frontend/callbacks/system_c/role_c/role_c.py b/dash-fastapi-frontend/callbacks/system_c/role_c/role_c.py index b419d9bf709ce0a3d01d2ac9639a532b7f04687d..de81624abc17d278a0a7dd567b1ec3644c0d9ada 100644 --- a/dash-fastapi-frontend/callbacks/system_c/role_c/role_c.py +++ b/dash-fastapi-frontend/callbacks/system_c/role_c/role_c.py @@ -3,6 +3,7 @@ import time import uuid from dash import dcc from dash.dependencies import Input, Output, State, ALL +from dash.exceptions import PreventUpdate import feffery_antd_components as fac import feffery_utils_components as fuc @@ -12,23 +13,32 @@ from api.menu import get_menu_tree_api @app.callback( - [Output('role-list-table', 'data', allow_duplicate=True), - Output('role-list-table', 'pagination', allow_duplicate=True), - Output('role-list-table', 'key'), - Output('role-list-table', 'selectedRowKeys'), - Output('api-check-token', 'data', allow_duplicate=True)], - [Input('role-search', 'nClicks'), - Input('role-refresh', 'nClicks'), - Input('role-list-table', 'pagination'), - Input('role-operations-store', 'data')], - [State('role-role_name-input', 'value'), - State('role-role_key-input', 'value'), - State('role-status-select', 'value'), - State('role-create_time-range', 'value'), - State('role-button-perms-container', 'data')], + output=dict( + role_table_data=Output('role-list-table', 'data', allow_duplicate=True), + role_table_pagination=Output('role-list-table', 'pagination', allow_duplicate=True), + role_table_key=Output('role-list-table', 'key'), + role_table_selectedrowkeys=Output('role-list-table', 'selectedRowKeys'), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True) + ), + inputs=dict( + search_click=Input('role-search', 'nClicks'), + refresh_click=Input('role-refresh', 'nClicks'), + pagination=Input('role-list-table', 'pagination'), + operations=Input('role-operations-store', 'data') + ), + state=dict( + role_name=State('role-role_name-input', 'value'), + role_key=State('role-role_key-input', 'value'), + status_select=State('role-status-select', 'value'), + create_time_range=State('role-create_time-range', 'value'), + button_perms=State('role-button-perms-container', 'data') + ), prevent_initial_call=True ) def get_role_table_data(search_click, refresh_click, pagination, operations, role_name, role_key, status_select, create_time_range, button_perms): + """ + 获取角色表格数据回调(进行表格相关增删查改操作后均会触发此回调) + """ create_time_start = None create_time_end = None @@ -69,9 +79,9 @@ def get_role_table_data(search_click, refresh_click, pagination, operations, rol ) for item in table_data: if item['status'] == '0': - item['status'] = dict(checked=True) + item['status'] = dict(checked=True, disabled=item['role_id'] == 1) else: - item['status'] = dict(checked=False) + item['status'] = dict(checked=False, disabled=item['role_id'] == 1) item['key'] = str(item['role_id']) if item['role_id'] == 1: item['operation'] = [] @@ -161,13 +171,26 @@ def get_role_table_data(search_click, refresh_click, pagination, operations, rol ] ) - return [table_data, table_pagination, str(uuid.uuid4()), None, {'timestamp': time.time()}] + return dict( + role_table_data=table_data, + role_table_pagination=table_pagination, + role_table_key=str(uuid.uuid4()), + role_table_selectedrowkeys=None, + api_check_token_trigger={'timestamp': time.time()} + ) - return [dash.no_update, dash.no_update, dash.no_update, dash.no_update, {'timestamp': time.time()}] + return dict( + role_table_data=dash.no_update, + role_table_pagination=dash.no_update, + role_table_key=dash.no_update, + role_table_selectedrowkeys=dash.no_update, + api_check_token_trigger={'timestamp': time.time()} + ) - return [dash.no_update] * 5 + raise PreventUpdate +# 重置角色搜索表单数据回调 app.clientside_callback( ''' (reset_click) => { @@ -187,6 +210,7 @@ app.clientside_callback( ) +# 隐藏/显示角色搜索表单回调 app.clientside_callback( ''' (hidden_click, hidden_status) => { @@ -213,6 +237,9 @@ app.clientside_callback( prevent_initial_call=True ) def change_role_edit_button_status(table_rows_selected): + """ + 根据选择的表格数据行数控制编辑按钮状态回调 + """ outputs_list = dash.ctx.outputs_list if outputs_list: if table_rows_selected: @@ -232,13 +259,14 @@ def change_role_edit_button_status(table_rows_selected): prevent_initial_call=True ) def change_role_delete_button_status(table_rows_selected): + """ + 根据选择的表格数据行数控制删除按钮状态回调 + """ outputs_list = dash.ctx.outputs_list if outputs_list: if table_rows_selected: if '1' in table_rows_selected: return True - if len(table_rows_selected) > 1: - return False return False @@ -254,6 +282,9 @@ def change_role_delete_button_status(table_rows_selected): prevent_initial_call=True ) def fold_unfold_role_menu(fold_unfold, menu_info): + """ + 新增和编辑表单中展开/折叠checkbox回调 + """ if menu_info: default_expanded_keys = [] for item in menu_info: @@ -275,6 +306,9 @@ def fold_unfold_role_menu(fold_unfold, menu_info): prevent_initial_call=True ) def all_none_role_menu_mode(all_none, menu_info): + """ + 新增和编辑表单中全选/全不选checkbox回调 + """ if menu_info: default_expanded_keys = [] for item in menu_info: @@ -297,6 +331,9 @@ def all_none_role_menu_mode(all_none, menu_info): prevent_initial_call=True ) def change_role_menu_mode(parent_children, current_role_menu): + """ + 新增和编辑表单中父子联动checkbox回调 + """ checked_menu = [] if parent_children: if current_role_menu: @@ -316,53 +353,63 @@ def change_role_menu_mode(parent_children, current_role_menu): @app.callback( - [Output('role-modal', 'visible', allow_duplicate=True), - Output('role-modal', 'title'), - Output('role-role_name', 'value'), - Output('role-role_key', 'value'), - Output('role-role_sort', 'value'), - Output('role-status', 'value'), - Output('role-menu-perms', 'treeData'), - Output('role-menu-perms', 'expandedKeys', allow_duplicate=True), - Output('role-menu-perms', 'checkedKeys', allow_duplicate=True), - Output('role-menu-perms', 'halfCheckedKeys', allow_duplicate=True), - Output('role-menu-store', 'data'), - Output('current-role-menu-store', 'data'), - Output('role-remark', 'value'), - Output('api-check-token', 'data', allow_duplicate=True), - Output('role-edit-id-store', 'data'), - Output('role-operations-store-bk', 'data')], - [Input({'type': 'role-operation-button', 'operation': ALL}, 'nClicks'), - Input({'type': 'role-operation-table', 'operation': ALL, 'index': ALL}, 'nClicks')], - State('role-list-table', 'selectedRowKeys'), + output=dict( + modal_visible=Output('role-modal', 'visible', allow_duplicate=True), + modal_title=Output('role-modal', 'title'), + form_value=Output({'type': 'role-form-value', 'index': ALL, 'required': ALL}, 'value'), + form_label_validate_status=Output({'type': 'role-form-label', 'index': ALL, 'required': True}, 'validateStatus', allow_duplicate=True), + form_label_validate_info=Output({'type': 'role-form-label', 'index': ALL, 'required': True}, 'help', allow_duplicate=True), + menu_perms_tree=Output('role-menu-perms', 'treeData'), + menu_perms_expandedkeys=Output('role-menu-perms', 'expandedKeys', allow_duplicate=True), + menu_perms_checkedkeys=Output('role-menu-perms', 'checkedKeys', allow_duplicate=True), + menu_perms_halfcheckedkeys=Output('role-menu-perms', 'halfCheckedKeys', allow_duplicate=True), + role_menu=Output('role-menu-store', 'data'), + current_role_menu=Output('current-role-menu-store', 'data'), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True), + edit_row_info=Output('role-edit-id-store', 'data'), + modal_type=Output('role-operations-store-bk', 'data') + ), + inputs=dict( + operation_click=Input({'type': 'role-operation-button', 'operation': ALL}, 'nClicks'), + button_click=Input({'type': 'role-operation-table', 'operation': ALL, 'index': ALL}, 'nClicks') + ), + state=dict( + selected_row_keys=State('role-list-table', 'selectedRowKeys') + ), prevent_initial_call=True ) def add_edit_role_modal(operation_click, button_click, selected_row_keys): + """ + 显示新增或编辑角色弹窗回调 + """ trigger_id = dash.ctx.triggered_id if trigger_id.operation in ['add', 'edit']: + # 获取所有输出表单项对应value的index + form_value_list = [x['id']['index'] for x in dash.ctx.outputs_list[2]] + # 获取所有输出表单项对应label的index + form_label_list = [x['id']['index'] for x in dash.ctx.outputs_list[3]] menu_params = dict(menu_name='', type='role') tree_info = get_menu_tree_api(menu_params) if tree_info.get('code') == 200: tree_data = tree_info['data'] if trigger_id.type == 'role-operation-button' and trigger_id.operation == 'add': - return [ - True, - '新增角色', - None, - None, - None, - '0', - tree_data[0], - [], - None, - None, - tree_data[1], - None, - None, - {'timestamp': time.time()}, - None, - {'type': 'add'} - ] + role_info = dict(role_name=None, role_key=None, role_sort=None, status='0', remark=None) + return dict( + modal_visible=True, + modal_title='新增角色', + form_value=[role_info.get(k) for k in form_value_list], + form_label_validate_status=[None] * len(form_label_list), + form_label_validate_info=[None] * len(form_label_list), + menu_perms_tree=tree_data[0], + menu_perms_expandedkeys=[], + menu_perms_checkedkeys=None, + menu_perms_halfcheckedkeys=None, + role_menu=tree_data[1], + current_role_menu=None, + api_check_token_trigger={'timestamp': time.time()}, + edit_row_info=None, + modal_type={'type': 'add'} + ) elif trigger_id.operation == 'edit': if trigger_id.type == 'role-operation-button': role_id = int(','.join(selected_row_keys)) @@ -384,125 +431,134 @@ def add_edit_role_modal(operation_click, button_click, selected_row_keys): if not has_children: checked_menu.append(str(item.get('menu_id'))) half_checked_menu = [x for x in checked_menu_all if x not in checked_menu] - return [ - True, - '编辑角色', - role_info.get('role').get('role_name'), - role_info.get('role').get('role_key'), - role_info.get('role').get('role_sort'), - role_info.get('role').get('status'), - tree_data[0], - [], - checked_menu, - half_checked_menu, - tree_data[1], - role_info.get('menu'), - role_info.get('role').get('remark'), - {'timestamp': time.time()}, - role_info.get('role') if role_info else None, - {'type': 'edit'} - ] - - return [dash.no_update] * 13 + [{'timestamp': time.time()}, None, None] - - return [dash.no_update] * 14 + [None, None] + return dict( + modal_visible=True, + modal_title='编辑角色', + form_value=[role_info.get('role').get(k) for k in form_value_list], + form_label_validate_status=[None] * len(form_label_list), + form_label_validate_info=[None] * len(form_label_list), + menu_perms_tree=tree_data[0], + menu_perms_expandedkeys=[], + menu_perms_checkedkeys=checked_menu, + menu_perms_halfcheckedkeys=half_checked_menu, + role_menu=tree_data[1], + current_role_menu=role_info.get('menu'), + api_check_token_trigger={'timestamp': time.time()}, + edit_row_info=role_info.get('role') if role_info else None, + modal_type={'type': 'edit'} + ) + + return dict( + modal_visible=dash.no_update, + modal_title=dash.no_update, + form_value=[dash.no_update] * len(form_value_list), + form_label_validate_status=[dash.no_update] * len(form_value_list), + form_label_validate_info=[dash.no_update] * len(form_value_list), + menu_perms_tree=dash.no_update, + menu_perms_expandedkeys=dash.no_update, + menu_perms_checkedkeys=dash.no_update, + menu_perms_halfcheckedkeys=dash.no_update, + role_menu=dash.no_update, + current_role_menu=dash.no_update, + api_check_token_trigger={'timestamp': time.time()}, + edit_row_info=None, + modal_type=None + ) + + raise PreventUpdate @app.callback( - [Output('role-role_name-form-item', 'validateStatus'), - Output('role-role_Key-form-item', 'validateStatus'), - Output('role-role_sort-form-item', 'validateStatus'), - Output('role-role_name-form-item', 'help'), - Output('role-role_Key-form-item', 'help'), - Output('role-role_sort-form-item', 'help'), - Output('role-modal', 'visible'), - Output('role-operations-store', 'data', allow_duplicate=True), - Output('api-check-token', 'data', allow_duplicate=True), - Output('global-message-container', 'children', allow_duplicate=True)], - Input('role-modal', 'okCounts'), - [State('role-operations-store-bk', 'data'), - State('role-edit-id-store', 'data'), - State('role-role_name', 'value'), - State('role-role_key', 'value'), - State('role-role_sort', 'value'), - State('role-status', 'value'), - State('role-menu-perms', 'checkedKeys'), - State('role-menu-perms', 'halfCheckedKeys'), - State('role-menu-perms-radio-parent-children', 'checked'), - State('role-remark', 'value')], + output=dict( + form_label_validate_status=Output({'type': 'role-form-label', 'index': ALL, 'required': True}, 'validateStatus', + allow_duplicate=True), + form_label_validate_info=Output({'type': 'role-form-label', 'index': ALL, 'required': True}, 'help', + allow_duplicate=True), + modal_visible=Output('role-modal', 'visible'), + operations=Output('role-operations-store', 'data', allow_duplicate=True), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True), + global_message_container=Output('global-message-container', 'children', allow_duplicate=True) + ), + inputs=dict( + confirm_trigger=Input('role-modal', 'okCounts') + ), + state=dict( + modal_type=State('role-operations-store-bk', 'data'), + edit_row_info=State('role-edit-id-store', 'data'), + form_value=State({'type': 'role-form-value', 'index': ALL, 'required': ALL}, 'value'), + form_label=State({'type': 'role-form-value', 'index': ALL, 'required': True}, 'placeholder'), + menu_checked_keys=State('role-menu-perms', 'checkedKeys'), + menu_half_checked_keys=State('role-menu-perms', 'halfCheckedKeys'), + parent_checked=State('role-menu-perms-radio-parent-children', 'checked') + ), prevent_initial_call=True ) -def role_confirm(confirm_trigger, operation_type, cur_role_info, role_name, role_key, role_sort, status, menu_checked_keys, menu_half_checked_keys, parent_checked, remark): +def role_confirm(confirm_trigger, modal_type, edit_row_info, form_value, form_label, menu_checked_keys, menu_half_checked_keys, parent_checked): + """ + 新增或编辑角色弹窗确认回调,实现新增或编辑操作 + """ if confirm_trigger: - if all([role_name, role_key, role_sort]): + # 获取所有输出表单项对应label的index + form_label_output_list = [x['id']['index'] for x in dash.ctx.outputs_list[0]] + # 获取所有输入表单项对应的value及label + form_value_state = {x['id']['index']: x.get('value') for x in dash.ctx.states_list[2]} + form_label_state = {x['id']['index']: x.get('value') for x in dash.ctx.states_list[3]} + if all([form_value_state.get(k) for k in form_label_output_list]): + menu_half_checked_keys = menu_half_checked_keys if menu_half_checked_keys else [] + menu_checked_keys = menu_checked_keys if menu_checked_keys else [] if parent_checked: menu_perms = menu_half_checked_keys + menu_checked_keys else: menu_perms = menu_checked_keys - params_add = dict(role_name=role_name, role_key=role_key, role_sort=role_sort, menu_id=','.join(menu_perms) if menu_perms else None, status=status, remark=remark) - params_edit = dict(role_id=cur_role_info.get('role_id') if cur_role_info else None, role_name=role_name, role_key=role_key, role_sort=role_sort, - menu_id=','.join(menu_perms) if menu_perms else '', status=status, remark=remark) + params_add = form_value_state + params_add['menu_id'] = ','.join(menu_perms) if menu_perms else None + params_edit = params_add.copy() + params_edit['role_id'] = edit_row_info.get('role_id') if edit_row_info else None api_res = {} - operation_type = operation_type.get('type') - if operation_type == 'add': + modal_type = modal_type.get('type') + if modal_type == 'add': api_res = add_role_api(params_add) - if operation_type == 'edit': + if modal_type == 'edit': api_res = edit_role_api(params_edit) if api_res.get('code') == 200: - if operation_type == 'add': - return [ - None, - None, - None, - None, - None, - None, - False, - {'type': 'add'}, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('新增成功', type='success') - ] - if operation_type == 'edit': - return [ - None, - None, - None, - None, - None, - None, - False, - {'type': 'edit'}, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('编辑成功', type='success') - ] - - return [ - None, - None, - None, - None, - None, - None, - dash.no_update, - dash.no_update, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('处理失败', type='error') - ] - - return [ - None if role_name else 'error', - None if role_key else 'error', - None if role_sort else 'error', - None if role_name else '请输入角色名称!', - None if role_key else '请输入权限字符!', - None if role_sort else '请输入角色排序!', - dash.no_update, - dash.no_update, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('处理失败', type='error') - ] + if modal_type == 'add': + return dict( + form_label_validate_status=[None] * len(form_label_output_list), + form_label_validate_info=[None] * len(form_label_output_list), + modal_visible=False, + operations={'type': 'add'}, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('新增成功', type='success') + ) + if modal_type == 'edit': + return dict( + form_label_validate_status=[None] * len(form_label_output_list), + form_label_validate_info=[None] * len(form_label_output_list), + modal_visible=False, + operations={'type': 'edit'}, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('编辑成功', type='success') + ) - return [dash.no_update] * 10 + return dict( + form_label_validate_status=[None] * len(form_label_output_list), + form_label_validate_info=[None] * len(form_label_output_list), + modal_visible=dash.no_update, + operations=dash.no_update, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('处理失败', type='error') + ) + + return dict( + form_label_validate_status=[None if form_value_state.get(k) else 'error' for k in form_label_output_list], + form_label_validate_info=[None if form_value_state.get(k) else form_label_state.get(k) for k in form_label_output_list], + modal_visible=dash.no_update, + operations=dash.no_update, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('处理失败', type='error') + ) + + raise PreventUpdate @app.callback( @@ -515,6 +571,9 @@ def role_confirm(confirm_trigger, operation_type, cur_role_info, role_name, role prevent_initial_call=True ) def table_switch_role_status(recently_switch_data_index, recently_switch_status, recently_switch_row): + """ + 表格内切换角色状态回调 + """ if recently_switch_data_index: if recently_switch_status: params = dict(role_id=int(recently_switch_row['key']), status='0', type='status') @@ -530,12 +589,12 @@ def table_switch_role_status(recently_switch_data_index, recently_switch_status, ] return [ - dash.no_update, + {'type': 'switch-status'}, {'timestamp': time.time()}, fuc.FefferyFancyMessage('修改失败', type='error') ] - return [dash.no_update] * 3 + raise PreventUpdate @app.callback( @@ -548,6 +607,9 @@ def table_switch_role_status(recently_switch_data_index, recently_switch_status, prevent_initial_call=True ) def role_delete_modal(operation_click, button_click, selected_row_keys): + """ + 显示删除角色二次确认弹窗回调 + """ trigger_id = dash.ctx.triggered_id if trigger_id.operation == 'delete': @@ -557,7 +619,7 @@ def role_delete_modal(operation_click, button_click, selected_row_keys): if trigger_id.type == 'role-operation-table': role_ids = trigger_id.index else: - return dash.no_update + raise PreventUpdate return [ f'是否确认删除角色编号为{role_ids}的角色?', @@ -565,7 +627,7 @@ def role_delete_modal(operation_click, button_click, selected_row_keys): {'role_ids': role_ids} ] - return [dash.no_update] * 3 + raise PreventUpdate @app.callback( @@ -577,6 +639,9 @@ def role_delete_modal(operation_click, button_click, selected_row_keys): prevent_initial_call=True ) def role_delete_confirm(delete_confirm, role_ids_data): + """ + 删除角色弹窗确认回调,实现删除操作 + """ if delete_confirm: params = role_ids_data @@ -594,7 +659,7 @@ def role_delete_confirm(delete_confirm, role_ids_data): fuc.FefferyFancyMessage('删除失败', type='error') ] - return [dash.no_update] * 3 + raise PreventUpdate @app.callback( @@ -606,6 +671,9 @@ def role_delete_confirm(delete_confirm, role_ids_data): prevent_initial_call=True ) def role_to_allocated_user_modal(allocated_click, allocated_user_search_nclick): + """ + 显示角色分配用户弹窗回调 + """ trigger_id = dash.ctx.triggered_id if trigger_id.operation == 'allocation': return [ @@ -614,7 +682,7 @@ def role_to_allocated_user_modal(allocated_click, allocated_user_search_nclick): trigger_id.index ] - return [dash.no_update] * 3 + raise PreventUpdate @app.callback( @@ -626,6 +694,9 @@ def role_to_allocated_user_modal(allocated_click, allocated_user_search_nclick): prevent_initial_call=True ) def export_role_list(export_click): + """ + 导出角色信息回调 + """ if export_click: export_role_res = export_role_list_api({}) if export_role_res.status_code == 200: @@ -645,7 +716,7 @@ def export_role_list(export_click): fuc.FefferyFancyMessage('导出失败', type='error') ] - return [dash.no_update] * 4 + raise PreventUpdate @app.callback( @@ -654,22 +725,12 @@ def export_role_list(export_click): prevent_initial_call=True ) def reset_role_export_status(data): + """ + 导出完成后重置下载组件数据回调,防止重复下载文件 + """ time.sleep(0.5) if data: return None - return dash.no_update - - -# 由于采用了自定义单元格元素,路由变化时需要重置selectedRows,不然会报错 -app.clientside_callback( - ''' - (url) => { - return null; - } - ''', - Output('role-list-table', 'selectedRows'), - Input('url-container', 'pathname'), - prevent_initial_call=True -) + raise PreventUpdate diff --git a/dash-fastapi-frontend/callbacks/system_c/user_c/allocate_role_c.py b/dash-fastapi-frontend/callbacks/system_c/user_c/allocate_role_c.py index a62052b449b83f80f40fcb07d26134e32fd297f0..5ddf787de2774f834e147a43961116a4691607b7 100644 --- a/dash-fastapi-frontend/callbacks/system_c/user_c/allocate_role_c.py +++ b/dash-fastapi-frontend/callbacks/system_c/user_c/allocate_role_c.py @@ -2,6 +2,7 @@ import dash import time import uuid from dash.dependencies import Input, Output, State, ALL, MATCH +from dash.exceptions import PreventUpdate import feffery_utils_components as fuc from server import app @@ -24,6 +25,9 @@ from api.user import get_allocated_role_list_api, get_unallocated_role_list_api, prevent_initial_call=True ) def get_allocate_role_table_data(search_click, refresh_click, pagination, operations, role_name, role_key, user_id, button_perms): + """ + 使用模式匹配回调MATCH模式,根据不同类型获取用户已分配角色列表及未分配角色列表(进行表格相关增删查改操作后均会触发此回调) + """ query_params = dict( user_id=int(user_id), @@ -76,9 +80,10 @@ def get_allocate_role_table_data(search_click, refresh_click, pagination, operat return [dash.no_update, dash.no_update, dash.no_update, dash.no_update] - return [dash.no_update] * 4 + raise PreventUpdate +# 重置分配角色搜索表单数据回调 app.clientside_callback( ''' (reset_click) => { @@ -96,6 +101,7 @@ app.clientside_callback( ) +# 隐藏/显示分配角色搜索表单回调 app.clientside_callback( ''' (hidden_click, hidden_status) => { @@ -122,6 +128,9 @@ app.clientside_callback( prevent_initial_call=True ) def change_allocated_role_delete_button_status(table_rows_selected): + """ + 根据选择的表格数据行数控制取批量消授权按钮状态回调 + """ outputs_list = dash.ctx.outputs_list if outputs_list: if table_rows_selected: @@ -129,7 +138,7 @@ def change_allocated_role_delete_button_status(table_rows_selected): return True - return dash.no_update + raise PreventUpdate @app.callback( @@ -140,11 +149,14 @@ def change_allocated_role_delete_button_status(table_rows_selected): prevent_initial_call=True ) def allocate_role_modal(add_click, unallocated_role): + """ + 分配角色弹框中添加角色按钮回调 + """ if add_click: return [True, unallocated_role + 1 if unallocated_role else 1] - return [dash.no_update] * 2 + raise PreventUpdate @app.callback( @@ -158,6 +170,9 @@ def allocate_role_modal(add_click, unallocated_role): prevent_initial_call=True ) def allocate_user_add_confirm(add_confirm, selected_row_keys, user_id): + """ + 添加角色确认回调,实现给用户分配角色操作 + """ if add_confirm: if selected_row_keys: @@ -185,7 +200,7 @@ def allocate_user_add_confirm(add_confirm, selected_row_keys, user_id): fuc.FefferyFancyMessage('请选择角色', type='error') ] - return [dash.no_update] * 4 + raise PreventUpdate @app.callback( @@ -201,6 +216,9 @@ def allocate_user_add_confirm(add_confirm, selected_row_keys, user_id): ) def allocate_role_delete_modal(operation_click, button_click, selected_row_keys, clicked_content, recently_button_clicked_row): + """ + 显示取消授权二次确认弹窗回调 + """ trigger_id = dash.ctx.triggered_id if trigger_id.type == 'allocate_role-operation-button' or ( trigger_id.type == 'allocate_role-list-table' and clicked_content == '取消授权'): @@ -219,7 +237,7 @@ def allocate_role_delete_modal(operation_click, button_click, role_ids ] - return [dash.no_update] * 3 + raise PreventUpdate @app.callback( @@ -232,6 +250,9 @@ def allocate_role_delete_modal(operation_click, button_click, prevent_initial_call=True ) def allocate_role_delete_confirm(delete_confirm, role_ids_data, user_id): + """ + 取消授权弹窗确认回调,实现取消授权操作 + """ if delete_confirm: params = {'user_ids': user_id, 'role_ids': role_ids_data} @@ -249,4 +270,4 @@ def allocate_role_delete_confirm(delete_confirm, role_ids_data, user_id): fuc.FefferyFancyMessage('取消授权失败', type='error') ] - return [dash.no_update] * 3 + raise PreventUpdate diff --git a/dash-fastapi-frontend/callbacks/system_c/user_c/profile_c/avatar_c.py b/dash-fastapi-frontend/callbacks/system_c/user_c/profile_c/avatar_c.py index 1e2cb444f9b8e352d17f2bd06351c093c3e2e85e..0930ec4d33752d37166ed368f39549ccc6a2f5f1 100644 --- a/dash-fastapi-frontend/callbacks/system_c/user_c/profile_c/avatar_c.py +++ b/dash-fastapi-frontend/callbacks/system_c/user_c/profile_c/avatar_c.py @@ -3,6 +3,7 @@ import feffery_utils_components as fuc import time import uuid from dash.dependencies import Input, Output, State +from dash.exceptions import PreventUpdate from server import app from api.user import change_user_avatar_api @@ -16,10 +17,13 @@ from api.user import change_user_avatar_api prevent_initial_call=True ) def avatar_cropper_modal_visible(n_clicks, user_avatar_image_info): + """ + 显示编辑头像弹窗回调 + """ if n_clicks: return [True, user_avatar_image_info] - return dash.no_update, dash.no_update + raise PreventUpdate @app.callback( @@ -28,11 +32,14 @@ def avatar_cropper_modal_visible(n_clicks, user_avatar_image_info): prevent_initial_call=True ) def upload_user_avatar(list_upload_task_record): + """ + 上传用户头像获取后端url回调 + """ if list_upload_task_record: return list_upload_task_record[-1].get('url') - return dash.no_update + raise PreventUpdate @app.callback( @@ -41,6 +48,9 @@ def upload_user_avatar(list_upload_task_record): prevent_initial_call=True ) def edit_user_avatar(src_data): + """ + 使用cropper.js编辑头像回调 + """ return """ // 创建新图像元素 @@ -127,6 +137,9 @@ def edit_user_avatar(src_data): prevent_initial_call=True ) def change_user_avatar_callback(submit_click, avatar_data): + """ + 提交编辑完成头像数据回调,实现更新头像操作 + """ if submit_click: params = dict(type='avatar', avatar=avatar_data['avatarBase64']) @@ -149,4 +162,4 @@ def change_user_avatar_callback(submit_click, avatar_data): dash.no_update ] - return [dash.no_update] * 5 + raise PreventUpdate diff --git a/dash-fastapi-frontend/callbacks/system_c/user_c/profile_c/reset_pwd_c.py b/dash-fastapi-frontend/callbacks/system_c/user_c/profile_c/reset_pwd_c.py index a5457d83e164dcd6b0aeece010398c8c3763c85b..ca81b66d2d2b6645e9f4b2e288e4204e5a109580 100644 --- a/dash-fastapi-frontend/callbacks/system_c/user_c/profile_c/reset_pwd_c.py +++ b/dash-fastapi-frontend/callbacks/system_c/user_c/profile_c/reset_pwd_c.py @@ -2,6 +2,7 @@ import dash import feffery_utils_components as fuc import time from dash.dependencies import Input, Output, State +from dash.exceptions import PreventUpdate from server import app from api.user import reset_user_password_api @@ -23,6 +24,9 @@ from api.user import reset_user_password_api prevent_initial_call=True ) def reset_submit_user_info(reset_click, old_password, new_password, confirm_password): + """ + 重置当前用户密码回调 + """ if reset_click: if all([old_password, new_password, confirm_password]): @@ -76,7 +80,7 @@ def reset_submit_user_info(reset_click, old_password, new_password, confirm_pass fuc.FefferyFancyMessage('修改失败', type='error'), ] - return [dash.no_update] * 8 + raise PreventUpdate @app.callback( @@ -85,7 +89,10 @@ def reset_submit_user_info(reset_click, old_password, new_password, confirm_pass prevent_initial_call=True ) def close_personal_info_modal(close_click): + """ + 关闭当前个人资料标签页回调 + """ if close_click: return '个人资料' - return dash.no_update + raise PreventUpdate diff --git a/dash-fastapi-frontend/callbacks/system_c/user_c/profile_c/user_info_c.py b/dash-fastapi-frontend/callbacks/system_c/user_c/profile_c/user_info_c.py index 6cdef31d617d3359dcf0d5ccc54bc3dcdf39fa25..6b2769d84537e601a4ecdaf328386f562195a5f9 100644 --- a/dash-fastapi-frontend/callbacks/system_c/user_c/profile_c/user_info_c.py +++ b/dash-fastapi-frontend/callbacks/system_c/user_c/profile_c/user_info_c.py @@ -2,6 +2,7 @@ import dash import feffery_utils_components as fuc import time from dash.dependencies import Input, Output, State +from dash.exceptions import PreventUpdate from server import app from api.user import change_user_info_api @@ -24,6 +25,9 @@ from api.user import change_user_info_api prevent_initial_call=True ) def reset_submit_user_info(reset_click, nick_name, phonenumber, email, sex): + """ + 修改当前用户信息回调 + """ if reset_click: if all([nick_name, phonenumber, email]): @@ -64,7 +68,7 @@ def reset_submit_user_info(reset_click, nick_name, phonenumber, email, sex): fuc.FefferyFancyMessage('修改失败', type='error'), ] - return [dash.no_update] * 8 + raise PreventUpdate @app.callback( @@ -73,7 +77,10 @@ def reset_submit_user_info(reset_click, nick_name, phonenumber, email, sex): prevent_initial_call=True ) def close_personal_info_modal(close_click): + """ + 关闭当前个人资料标签页回调 + """ if close_click: return '个人资料' - return dash.no_update + raise PreventUpdate diff --git a/dash-fastapi-frontend/callbacks/system_c/user_c/user_c.py b/dash-fastapi-frontend/callbacks/system_c/user_c/user_c.py index 9e3ebbcd6a820f7185e2783325a4796204c34fa8..b5c03cc00c685ca4931f429714bb064a3a57c6b0 100644 --- a/dash-fastapi-frontend/callbacks/system_c/user_c/user_c.py +++ b/dash-fastapi-frontend/callbacks/system_c/user_c/user_c.py @@ -3,6 +3,7 @@ import time import uuid from dash import dcc from dash.dependencies import Input, Output, State, ALL +from dash.exceptions import PreventUpdate import feffery_utils_components as fuc from server import app @@ -30,25 +31,34 @@ def get_search_dept_tree(dept_input): @app.callback( - [Output('user-list-table', 'data', allow_duplicate=True), - Output('user-list-table', 'pagination', allow_duplicate=True), - Output('user-list-table', 'key'), - Output('user-list-table', 'selectedRowKeys'), - Output('api-check-token', 'data', allow_duplicate=True)], - [Input('dept-tree', 'selectedKeys'), - Input('user-search', 'nClicks'), - Input('user-refresh', 'nClicks'), - Input('user-list-table', 'pagination'), - Input('user-operations-store', 'data')], - [State('user-user_name-input', 'value'), - State('user-phone_number-input', 'value'), - State('user-status-select', 'value'), - State('user-create_time-range', 'value'), - State('user-button-perms-container', 'data')], + output=dict( + user_table_data=Output('user-list-table', 'data', allow_duplicate=True), + user_table_pagination=Output('user-list-table', 'pagination', allow_duplicate=True), + user_table_key=Output('user-list-table', 'key'), + user_table_selectedrowkeys=Output('user-list-table', 'selectedRowKeys'), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True) + ), + inputs=dict( + selected_dept_tree=Input('dept-tree', 'selectedKeys'), + search_click=Input('user-search', 'nClicks'), + refresh_click=Input('user-refresh', 'nClicks'), + pagination=Input('user-list-table', 'pagination'), + operations=Input('user-operations-store', 'data') + ), + state=dict( + user_name=State('user-user_name-input', 'value'), + phone_number=State('user-phone_number-input', 'value'), + status_select=State('user-status-select', 'value'), + create_time_range=State('user-create_time-range', 'value'), + button_perms=State('user-button-perms-container', 'data') + ), prevent_initial_call=True ) def get_user_table_data_by_dept_tree(selected_dept_tree, search_click, refresh_click, pagination, operations, user_name, phone_number, status_select, create_time_range, button_perms): + """ + 获取用户表格数据回调(进行表格相关增删查改操作后均会触发此回调) + """ dept_id = None create_time_start = None create_time_end = None @@ -119,13 +129,26 @@ def get_user_table_data_by_dept_tree(selected_dept_tree, search_click, refresh_c } if 'system:user:edit' in button_perms else None ] - return [table_data, table_pagination, str(uuid.uuid4()), None, {'timestamp': time.time()}] + return dict( + user_table_data=table_data, + user_table_pagination=table_pagination, + user_table_key=str(uuid.uuid4()), + user_table_selectedrowkeys=None, + api_check_token_trigger={'timestamp': time.time()} + ) - return [dash.no_update, dash.no_update, dash.no_update, dash.no_update, {'timestamp': time.time()}] + return dict( + user_table_data=dash.no_update, + user_table_pagination=dash.no_update, + user_table_key=dash.no_update, + user_table_selectedrowkeys=dash.no_update, + api_check_token_trigger={'timestamp': time.time()} + ) - return [dash.no_update] * 5 + raise PreventUpdate +# 重置用户搜索表单数据回调 app.clientside_callback( ''' (reset_click) => { @@ -146,6 +169,7 @@ app.clientside_callback( ) +# 隐藏/显示用户搜索表单回调 app.clientside_callback( ''' (hidden_click, hidden_status) => { @@ -172,6 +196,9 @@ app.clientside_callback( prevent_initial_call=True ) def change_user_edit_button_status(table_rows_selected): + """ + 根据选择的表格数据行数控制编辑按钮状态回调 + """ outputs_list = dash.ctx.outputs_list if outputs_list: if table_rows_selected: @@ -182,7 +209,7 @@ def change_user_edit_button_status(table_rows_selected): return True - return dash.no_update + raise PreventUpdate @app.callback( @@ -191,32 +218,49 @@ def change_user_edit_button_status(table_rows_selected): prevent_initial_call=True ) def change_user_delete_button_status(table_rows_selected): + """ + 根据选择的表格数据行数控制删除按钮状态回调 + """ outputs_list = dash.ctx.outputs_list if outputs_list: if table_rows_selected: if '1' in table_rows_selected: return True - if len(table_rows_selected) > 1: - return False return False return True - return dash.no_update + raise PreventUpdate @app.callback( - [Output('user-add-modal', 'visible', allow_duplicate=True), - Output('user-add-dept_id', 'treeData'), - Output('user-add-post', 'options'), - Output('user-add-role', 'options'), - Output('api-check-token', 'data', allow_duplicate=True)], - Input('user-add', 'nClicks'), + output=dict( + modal_visible=Output('user-add-modal', 'visible', allow_duplicate=True), + dept_tree=Output({'type': 'user_add-form-value', 'index': 'dept_id'}, 'treeData'), + form_value=Output({'type': 'user_add-form-value', 'index': ALL}, 'value'), + form_label_validate_status=Output({'type': 'user_add-form-label', 'index': ALL, 'required': True}, 'validateStatus', allow_duplicate=True), + form_label_validate_info=Output({'type': 'user_add-form-label', 'index': ALL, 'required': True}, 'help', allow_duplicate=True), + user_post=Output('user-add-post', 'value'), + user_role=Output('user-add-role', 'value'), + post_option=Output('user-add-post', 'options'), + role_option=Output('user-add-role', 'options'), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True) + ), + inputs=dict( + add_click=Input('user-add', 'nClicks') + ), prevent_initial_call=True ) def add_user_modal(add_click): + """ + 显示新增用户弹窗回调 + """ if add_click: + # 获取所有输出表单项对应value的index + form_value_list = [x['id']['index'] for x in dash.ctx.outputs_list[2]] + # 获取所有输出表单项对应label的index + form_label_list = [x['id']['index'] for x in dash.ctx.outputs_list[3]] dept_params = dict(dept_name='') tree_info = get_dept_tree_api(dept_params) post_option_info = get_post_select_option_api() @@ -225,126 +269,138 @@ def add_user_modal(add_click): tree_data = tree_info['data'] post_option = post_option_info['data'] role_option = role_option_info['data'] + user_info = dict(nick_name=None, dept_id=None, phonenumber=None, email=None, user_name=None, password=None, sex=None, status='0', remark=None) + + return dict( + modal_visible=True, + dept_tree=tree_data, + form_value=[user_info.get(k) for k in form_value_list], + form_label_validate_status=[None] * len(form_label_list), + form_label_validate_info=[None] * len(form_label_list), + user_post=None, + user_role=None, + post_option=[dict(label=item['post_name'], value=item['post_id']) for item in post_option], + role_option=[dict(label=item['role_name'], value=item['role_id']) for item in role_option], + api_check_token_trigger={'timestamp': time.time()} + ) - return [ - True, - tree_data, - [dict(label=item['post_name'], value=item['post_id']) for item in post_option], - [dict(label=item['role_name'], value=item['role_id']) for item in role_option], - {'timestamp': time.time()} - ] - - return [dash.no_update] * 4 + [{'timestamp': time.time()}] + return dict( + modal_visible=dash.no_update, + dept_tree=dash.no_update, + form_value=[dash.no_update] * len(form_value_list), + form_label_validate_status=[dash.no_update] * len(form_label_list), + form_label_validate_info=[dash.no_update] * len(form_label_list), + user_post=dash.no_update, + user_role=dash.no_update, + post_option=dash.no_update, + role_option=dash.no_update, + api_check_token_trigger={'timestamp': time.time()} + ) - return [dash.no_update] * 5 + raise PreventUpdate @app.callback( - [Output('user-add-nick_name-form-item', 'validateStatus'), - Output('user-add-user_name-form-item', 'validateStatus'), - Output('user-add-password-form-item', 'validateStatus'), - Output('user-add-nick_name-form-item', 'help'), - Output('user-add-user_name-form-item', 'help'), - Output('user-add-password-form-item', 'help'), - Output('user-add-modal', 'visible', allow_duplicate=True), - Output('user-operations-store', 'data', allow_duplicate=True), - Output('api-check-token', 'data', allow_duplicate=True), - Output('global-message-container', 'children', allow_duplicate=True)], - Input('user-add-modal', 'okCounts'), - [State('user-add-nick_name', 'value'), - State('user-add-dept_id', 'value'), - State('user-add-phone_number', 'value'), - State('user-add-email', 'value'), - State('user-add-user_name', 'value'), - State('user-add-password', 'value'), - State('user-add-sex', 'value'), - State('user-add-status', 'value'), - State('user-add-post', 'value'), - State('user-add-role', 'value'), - State('user-add-remark', 'value')], + output=dict( + form_label_validate_status=Output({'type': 'user_add-form-label', 'index': ALL, 'required': True}, 'validateStatus', allow_duplicate=True), + form_label_validate_info=Output({'type': 'user_add-form-label', 'index': ALL, 'required': True}, 'help', allow_duplicate=True), + modal_visible=Output('user-add-modal', 'visible', allow_duplicate=True), + operations=Output('user-operations-store', 'data', allow_duplicate=True), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True), + global_message_container=Output('global-message-container', 'children', allow_duplicate=True) + ), + inputs=dict( + add_confirm=Input('user-add-modal', 'okCounts') + ), + state=dict( + post=State('user-add-post', 'value'), + role=State('user-add-role', 'value'), + form_value=State({'type': 'user_add-form-value', 'index': ALL}, 'value'), + form_label=State({'type': 'user_add-form-label', 'index': ALL, 'required': True}, 'label') + ), prevent_initial_call=True ) -def usr_add_confirm(add_confirm, nick_name, dept_id, phone_number, email, user_name, password, sex, status, post, role, - remark): +def usr_add_confirm(add_confirm, post, role, form_value, form_label): if add_confirm: - - if all([nick_name, user_name, password]): - params = dict(nick_name=nick_name, dept_id=dept_id, phonenumber=phone_number, - email=email, user_name=user_name, password=password, sex=sex, - status=status, post_id=','.join(map(str, post)) if post else '', - role_id=','.join(map(str, role)) if role else '', remark=remark) + # 获取所有输出表单项对应label的index + form_label_output_list = [x['id']['index'] for x in dash.ctx.outputs_list[0]] + # 获取所有输入表单项对应的value及label + form_value_state = {x['id']['index']: x.get('value') for x in dash.ctx.states_list[-2]} + form_label_state = {x['id']['index']: x.get('value') for x in dash.ctx.states_list[-1]} + + if all([form_value_state.get(k) for k in form_label_output_list]): + params = form_value_state + params['post_id'] = ','.join(map(str, post)) if post else '' + params['role_id'] = ','.join(map(str, role)) if role else '' add_button_result = add_user_api(params) if add_button_result['code'] == 200: - return [ - None, - None, - None, - None, - None, - None, - False, - {'type': 'add'}, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('新增成功', type='success') - ] - - return [ - None, - None, - None, - None, - None, - None, - dash.no_update, - dash.no_update, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('新增失败', type='error') - ] + return dict( + form_label_validate_status=[None] * len(form_label_output_list), + form_label_validate_info=[None] * len(form_label_output_list), + modal_visible=False, + operations={'type': 'add'}, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('新增成功', type='success') + ) + + return dict( + form_label_validate_status=[None] * len(form_label_output_list), + form_label_validate_info=[None] * len(form_label_output_list), + modal_visible=dash.no_update, + operations=dash.no_update, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('新增失败', type='error') + ) - return [ - None if nick_name else 'error', - None if user_name else 'error', - None if password else 'error', - None if nick_name else '请输入用户昵称!', - None if user_name else '请输入用户名称!', - None if password else '请输入用户密码!', - dash.no_update, - dash.no_update, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('新增失败', type='error') - ] + return dict( + form_label_validate_status=[None if form_value_state.get(k) else 'error' for k in form_label_output_list], + form_label_validate_info=[None if form_value_state.get(k) else f'{form_label_state.get(k)}不能为空!' for k in form_label_output_list], + modal_visible=dash.no_update, + operations=dash.no_update, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('新增失败', type='error') + ) - return [dash.no_update] * 10 + raise PreventUpdate @app.callback( - [Output('user-edit-modal', 'visible', allow_duplicate=True), - Output('user-edit-dept_id', 'treeData'), - Output('user-edit-post', 'options'), - Output('user-edit-role', 'options'), - Output('user-edit-nick_name', 'value'), - Output('user-edit-dept_id', 'value'), - Output('user-edit-phone_number', 'value'), - Output('user-edit-email', 'value'), - Output('user-edit-sex', 'value'), - Output('user-edit-status', 'value'), - Output('user-edit-post', 'value'), - Output('user-edit-role', 'value'), - Output('user-edit-remark', 'value'), - Output('user-edit-id-store', 'data'), - Output('api-check-token', 'data', allow_duplicate=True)], - [Input({'type': 'user-operation-button', 'index': ALL}, 'nClicks'), - Input('user-list-table', 'nClicksDropdownItem')], - [State('user-list-table', 'selectedRowKeys'), - State('user-list-table', 'recentlyClickedDropdownItemTitle'), - State('user-list-table', 'recentlyDropdownItemClickedRow')], + output=dict( + modal_visible=Output('user-edit-modal', 'visible', allow_duplicate=True), + dept_tree=Output({'type': 'user_edit-form-value', 'index': 'dept_id'}, 'treeData'), + form_value=Output({'type': 'user_edit-form-value', 'index': ALL}, 'value'), + form_label_validate_status=Output({'type': 'user_edit-form-label', 'index': ALL, 'required': True}, 'validateStatus', allow_duplicate=True), + form_label_validate_info=Output({'type': 'user_edit-form-label', 'index': ALL, 'required': True}, 'help', allow_duplicate=True), + user_post=Output('user-edit-post', 'value'), + user_role=Output('user-edit-role', 'value'), + post_option=Output('user-edit-post', 'options'), + role_option=Output('user-edit-role', 'options'), + edit_row_info=Output('user-edit-id-store', 'data'), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True) + ), + inputs=dict( + operation_click=Input({'type': 'user-operation-button', 'index': ALL}, 'nClicks'), + dropdown_click=Input('user-list-table', 'nClicksDropdownItem') + ), + state=dict( + selected_row_keys=State('user-list-table', 'selectedRowKeys'), + recently_clicked_dropdown_item_title=State('user-list-table', 'recentlyClickedDropdownItemTitle'), + recently_dropdown_item_clicked_row=State('user-list-table', 'recentlyDropdownItemClickedRow') + ), prevent_initial_call=True ) def user_edit_modal(operation_click, dropdown_click, selected_row_keys, recently_clicked_dropdown_item_title, recently_dropdown_item_clicked_row): + """ + 显示编辑用户弹窗回调 + """ trigger_id = dash.ctx.triggered_id if trigger_id == {'index': 'edit', 'type': 'user-operation-button'} or (trigger_id == 'user-list-table' and recently_clicked_dropdown_item_title == '修改'): + # 获取所有输出表单项对应value的index + form_value_list = [x['id']['index'] for x in dash.ctx.outputs_list[2]] + # 获取所有输出表单项对应label的index + form_label_list = [x['id']['index'] for x in dash.ctx.outputs_list[3]] dept_params = dict(dept_name='') tree_data = get_dept_tree_api(dept_params)['data'] @@ -357,97 +413,111 @@ def user_edit_modal(operation_click, dropdown_click, if recently_clicked_dropdown_item_title == '修改': user_id = int(recently_dropdown_item_clicked_row['key']) else: - return [dash.no_update] * 15 + raise PreventUpdate edit_button_info = get_user_detail_api(user_id) if edit_button_info['code'] == 200: edit_button_result = edit_button_info['data'] user = edit_button_result['user'] - dept = edit_button_result['dept'] role = edit_button_result['role'] post = edit_button_result['post'] - return [ - True, - tree_data, - [dict(label=item['post_name'], value=item['post_id']) for item in post_option if item] or [], - [dict(label=item['role_name'], value=item['role_id']) for item in role_option if item] or [], - user['nick_name'], - dept['dept_id'] if dept else None, - user['phonenumber'], - user['email'], - user['sex'], - user['status'], - [item['post_id'] for item in post if item] or [], - [item['role_id'] for item in role if item] or [], - user['remark'], - {'user_id': user_id}, - {'timestamp': time.time()} - ] + return dict( + modal_visible=True, + dept_tree=tree_data, + form_value=[user.get(k) for k in form_value_list], + form_label_validate_status=[None] * len(form_label_list), + form_label_validate_info=[None] * len(form_label_list), + user_post=[item['post_id'] for item in post if item] or [], + user_role=[item['role_id'] for item in role if item] or [], + post_option=[dict(label=item['post_name'], value=item['post_id']) for item in post_option if item] or [], + role_option=[dict(label=item['role_name'], value=item['role_id']) for item in role_option if item] or [], + edit_row_info={'user_id': user_id}, + api_check_token_trigger={'timestamp': time.time()} + ) - return [dash.no_update] * 14 + [{'timestamp': time.time()}] + return dict( + modal_visible=dash.no_update, + dept_tree=dash.no_update, + form_value=[dash.no_update] * len(form_value_list), + form_label_validate_status=[dash.no_update] * len(form_label_list), + form_label_validate_info=[dash.no_update] * len(form_label_list), + user_post=dash.no_update, + user_role=dash.no_update, + post_option=dash.no_update, + role_option=dash.no_update, + edit_row_info=dash.no_update, + api_check_token_trigger={'timestamp': time.time()} + ) - return [dash.no_update] * 15 + raise PreventUpdate @app.callback( - [Output('user-edit-nick_name-form-item', 'validateStatus'), - Output('user-edit-nick_name-form-item', 'help'), - Output('user-edit-modal', 'visible', allow_duplicate=True), - Output('user-operations-store', 'data', allow_duplicate=True), - Output('api-check-token', 'data', allow_duplicate=True), - Output('global-message-container', 'children', allow_duplicate=True)], - Input('user-edit-modal', 'okCounts'), - [State('user-edit-nick_name', 'value'), - State('user-edit-dept_id', 'value'), - State('user-edit-phone_number', 'value'), - State('user-edit-email', 'value'), - State('user-edit-sex', 'value'), - State('user-edit-status', 'value'), - State('user-edit-post', 'value'), - State('user-edit-role', 'value'), - State('user-edit-remark', 'value'), - State('user-edit-id-store', 'data')], + output=dict( + form_label_validate_status=Output({'type': 'user_edit-form-label', 'index': ALL, 'required': True}, 'validateStatus', allow_duplicate=True), + form_label_validate_info=Output({'type': 'user_edit-form-label', 'index': ALL, 'required': True}, 'help', allow_duplicate=True), + modal_visible=Output('user-edit-modal', 'visible', allow_duplicate=True), + operations=Output('user-operations-store', 'data', allow_duplicate=True), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True), + global_message_container=Output('global-message-container', 'children', allow_duplicate=True) + ), + inputs=dict( + edit_confirm=Input('user-edit-modal', 'okCounts') + ), + state=dict( + post=State('user-edit-post', 'value'), + role=State('user-edit-role', 'value'), + edit_row_info=State('user-edit-id-store', 'data'), + form_value=State({'type': 'user_edit-form-value', 'index': ALL}, 'value'), + form_label=State({'type': 'user_edit-form-label', 'index': ALL, 'required': True}, 'label') + ), prevent_initial_call=True ) -def usr_edit_confirm(edit_confirm, nick_name, dept_id, phone_number, email, sex, status, post, role, remark, user_id): +def usr_edit_confirm(edit_confirm, edit_row_info, post, role, form_value, form_label): if edit_confirm: - - if all([nick_name]): - params = dict(user_id=user_id['user_id'], nick_name=nick_name, dept_id=dept_id if dept_id else -1, - phonenumber=phone_number, email=email, sex=sex, status=status, - post_id=','.join(map(str, post)), role_id=','.join(map(str, role)), remark=remark) + # 获取所有输出表单项对应label的index + form_label_output_list = [x['id']['index'] for x in dash.ctx.outputs_list[0]] + # 获取所有输入表单项对应的value及label + form_value_state = {x['id']['index']: x.get('value') for x in dash.ctx.states_list[-2]} + form_label_state = {x['id']['index']: x.get('value') for x in dash.ctx.states_list[-1]} + + if all([form_value_state.get(k) for k in form_label_output_list]): + params = form_value_state + params['user_id'] = edit_row_info.get('user_id') if edit_row_info else None + params['post_id'] = ','.join(map(str, post)) if post else '' + params['role_id'] = ','.join(map(str, role)) if role else '' edit_button_result = edit_user_api(params) if edit_button_result['code'] == 200: - return [ - None, - None, - False, - {'type': 'edit'}, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('编辑成功', type='success') - ] - - return [ - None, - None, - dash.no_update, - dash.no_update, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('编辑失败', type='error') - ] + return dict( + form_label_validate_status=[None] * len(form_label_output_list), + form_label_validate_info=[None] * len(form_label_output_list), + modal_visible=False, + operations={'type': 'edit'}, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('编辑成功', type='success') + ) + + return dict( + form_label_validate_status=[None] * len(form_label_output_list), + form_label_validate_info=[None] * len(form_label_output_list), + modal_visible=dash.no_update, + operations=dash.no_update, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('编辑失败', type='error') + ) - return [ - None if nick_name else 'error', - None if nick_name else '请输入用户昵称!', - dash.no_update, - dash.no_update, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('编辑失败', type='error') - ] + return dict( + form_label_validate_status=[None if form_value_state.get(k) else 'error' for k in form_label_output_list], + form_label_validate_info=[None if form_value_state.get(k) else f'{form_label_state.get(k)}不能为空!' for k in form_label_output_list], + modal_visible=dash.no_update, + operations=dash.no_update, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('编辑失败', type='error') + ) - return [dash.no_update] * 6 + raise PreventUpdate @app.callback( @@ -460,6 +530,9 @@ def usr_edit_confirm(edit_confirm, nick_name, dept_id, phone_number, email, sex, prevent_initial_call=True ) def table_switch_user_status(recently_switch_data_index, recently_switch_status, recently_switch_row): + """ + 表格内切换用户状态回调 + """ if recently_switch_data_index: if recently_switch_status: params = dict(user_id=int(recently_switch_row['key']), status='0', type='status') @@ -475,12 +548,12 @@ def table_switch_user_status(recently_switch_data_index, recently_switch_status, ] return [ - dash.no_update, + {'type': 'switch-status'}, {'timestamp': time.time()}, fuc.FefferyFancyMessage('修改失败', type='error') ] - return [dash.no_update] * 3 + raise PreventUpdate @app.callback( @@ -496,6 +569,9 @@ def table_switch_user_status(recently_switch_data_index, recently_switch_status, ) def user_delete_modal(operation_click, dropdown_click, selected_row_keys, recently_clicked_dropdown_item_title, recently_dropdown_item_clicked_row): + """ + 显示删除用户二次确认弹窗回调 + """ trigger_id = dash.ctx.triggered_id if trigger_id == {'index': 'delete', 'type': 'user-operation-button'} or (trigger_id == 'user-list-table' and recently_clicked_dropdown_item_title == '删除'): @@ -505,7 +581,7 @@ def user_delete_modal(operation_click, dropdown_click, if recently_clicked_dropdown_item_title == '删除': user_ids = recently_dropdown_item_clicked_row['key'] else: - return [dash.no_update] * 3 + raise PreventUpdate return [ f'是否确认删除用户编号为{user_ids}的用户?', @@ -513,7 +589,7 @@ def user_delete_modal(operation_click, dropdown_click, {'user_ids': user_ids} ] - return [dash.no_update] * 3 + raise PreventUpdate @app.callback( @@ -525,6 +601,9 @@ def user_delete_modal(operation_click, dropdown_click, prevent_initial_call=True ) def user_delete_confirm(delete_confirm, user_ids_data): + """ + 删除用户弹窗确认回调,实现删除操作 + """ if delete_confirm: params = user_ids_data @@ -542,7 +621,7 @@ def user_delete_confirm(delete_confirm, user_ids_data): fuc.FefferyFancyMessage('删除失败', type='error') ] - return [dash.no_update] * 3 + raise PreventUpdate @app.callback( @@ -555,11 +634,14 @@ def user_delete_confirm(delete_confirm, user_ids_data): prevent_initial_call=True ) def user_reset_password_modal(dropdown_click, recently_clicked_dropdown_item_title, recently_dropdown_item_clicked_row): + """ + 显示重置用户密码弹窗回调 + """ if dropdown_click: if recently_clicked_dropdown_item_title == '重置密码': user_id = recently_dropdown_item_clicked_row['key'] else: - return [dash.no_update] * 3 + raise PreventUpdate return [ True, @@ -567,7 +649,7 @@ def user_reset_password_modal(dropdown_click, recently_clicked_dropdown_item_tit None ] - return [dash.no_update] * 3 + raise PreventUpdate @app.callback( @@ -580,6 +662,9 @@ def user_reset_password_modal(dropdown_click, recently_clicked_dropdown_item_tit prevent_initial_call=True ) def user_reset_password_confirm(reset_confirm, user_id_data, reset_password): + """ + 重置用户密码弹窗确认回调,实现重置密码操作 + """ if reset_confirm: user_id_data['password'] = reset_password @@ -598,7 +683,7 @@ def user_reset_password_confirm(reset_confirm, user_id_data, reset_password): fuc.FefferyFancyMessage('重置失败', type='error') ] - return [dash.no_update] * 3 + raise PreventUpdate @app.callback( @@ -612,6 +697,9 @@ def user_reset_password_confirm(reset_confirm, user_id_data, reset_password): prevent_initial_call=True ) def role_to_allocated_user_modal(dropdown_click, recently_clicked_dropdown_item_title, recently_dropdown_item_clicked_row, allocated_role_search_nclick): + """ + 显示用户分配角色弹窗回调 + """ if dropdown_click and recently_clicked_dropdown_item_title == '分配角色': return [ @@ -620,9 +708,10 @@ def role_to_allocated_user_modal(dropdown_click, recently_clicked_dropdown_item_ recently_dropdown_item_clicked_row['key'] ] - return [dash.no_update] * 3 + raise PreventUpdate +# 显示用户导入弹窗及重置上传弹窗组件状态回调 app.clientside_callback( ''' (nClicks) => { @@ -652,52 +741,61 @@ app.clientside_callback( @app.callback( - [Output('user-import-confirm-modal', 'confirmLoading'), - Output('batch-result-modal', 'visible'), - Output('batch-result-content', 'children'), - Output('user-operations-store', 'data', allow_duplicate=True), - Output('api-check-token', 'data', allow_duplicate=True), - Output('global-message-container', 'children', allow_duplicate=True)], - Input('user-import-confirm-modal', 'okCounts'), - [State('user-upload-choose', 'listUploadTaskRecord'), - State('user-import-update-check', 'checked')], + output=dict( + confirm_loading=Output('user-import-confirm-modal', 'confirmLoading'), + modal_visible=Output('batch-result-modal', 'visible'), + batch_result=Output('batch-result-content', 'children'), + operations=Output('user-operations-store', 'data', allow_duplicate=True), + api_check_token_trigger=Output('api-check-token', 'data', allow_duplicate=True), + global_message_container=Output('global-message-container', 'children', allow_duplicate=True) + ), + inputs=dict( + import_confirm=Input('user-import-confirm-modal', 'okCounts') + ), + state=dict( + list_upload_task_record=State('user-upload-choose', 'listUploadTaskRecord'), + is_update=State('user-import-update-check', 'checked') + ), prevent_initial_call=True ) def user_import_confirm(import_confirm, list_upload_task_record, is_update): + """ + 用户导入弹窗确认回调,实现批量导入用户操作 + """ if import_confirm: if list_upload_task_record: url = list_upload_task_record[-1].get('url') batch_param = dict(url=url, is_update=is_update) batch_import_result = batch_import_user_api(batch_param) if batch_import_result.get('code') == 200: - return [ - False, - True if batch_import_result.get('message') else False, - batch_import_result.get('message'), - {'type': 'batch-import'}, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('导入成功', type='success') - ] - - return [ - False, - True, - batch_import_result.get('message'), - dash.no_update, - {'timestamp': time.time()}, - fuc.FefferyFancyMessage('导入失败', type='error') - ] + return dict( + confirm_loading=False, + modal_visible=True if batch_import_result.get('message') else False, + batch_result=batch_import_result.get('message'), + operations={'type': 'batch-import'}, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('导入成功', type='success') + ) + + return dict( + confirm_loading=False, + modal_visible=True, + batch_result=batch_import_result.get('message'), + operations=dash.no_update, + api_check_token_trigger={'timestamp': time.time()}, + global_message_container=fuc.FefferyFancyMessage('导入失败', type='error') + ) else: - return [ - False, - dash.no_update, - dash.no_update, - dash.no_update, - dash.no_update, - fuc.FefferyFancyMessage('请上传需要导入的文件', type='error') - ] + return dict( + confirm_loading=False, + modal_visible=dash.no_update, + batch_result=dash.no_update, + operations=dash.no_update, + api_check_token_trigger=dash.no_update, + global_message_container=fuc.FefferyFancyMessage('请上传需要导入的文件', type='error') + ) - return [dash.no_update] * 6 + raise PreventUpdate @app.callback( @@ -710,6 +808,9 @@ def user_import_confirm(import_confirm, list_upload_task_record, is_update): prevent_initial_call=True ) def export_user_list(export_click, download_click): + """ + 导出用户信息回调 + """ trigger_id = dash.ctx.triggered_id if export_click or download_click: @@ -751,7 +852,7 @@ def export_user_list(export_click, download_click): fuc.FefferyFancyMessage('下载失败', type='error') ] - return [dash.no_update] * 4 + raise PreventUpdate @app.callback( @@ -760,9 +861,12 @@ def export_user_list(export_click, download_click): prevent_initial_call=True ) def reset_user_export_status(data): + """ + 导出完成后重置下载组件数据回调,防止重复下载文件 + """ time.sleep(0.5) if data: return None - return dash.no_update + raise PreventUpdate diff --git a/dash-fastapi-frontend/views/monitor/job/__init__.py b/dash-fastapi-frontend/views/monitor/job/__init__.py index 2ac8bf4a5dc2e72472d62f622389f203f562417a..7785e341dea1a429551ad7703d9b8178b013831c 100644 --- a/dash-fastapi-frontend/views/monitor/job/__init__.py +++ b/dash-fastapi-frontend/views/monitor/job/__init__.py @@ -415,13 +415,20 @@ def render(button_perms): fac.AntdCol( fac.AntdFormItem( fac.AntdInput( - id='job-job_name', + id={ + 'type': 'job-form-value', + 'index': 'job_name' + }, placeholder='请输入任务名称', style={ 'width': '100%' } ), - id='job-job_name-form-item', + id={ + 'type': 'job-form-label', + 'index': 'job_name', + 'required': True + }, required=True, label='任务名称', labelCol={ @@ -436,14 +443,21 @@ def render(button_perms): fac.AntdCol( fac.AntdFormItem( fac.AntdSelect( - id='job-job_group', + id={ + 'type': 'job-form-value', + 'index': 'job_group' + }, placeholder='请选择任务分组', options=option, style={ 'width': '100%' } ), - id='job-job_group-form-item', + id={ + 'type': 'job-form-label', + 'index': 'job_group', + 'required': False + }, label='任务分组', labelCol={ 'span': 6 @@ -462,13 +476,20 @@ def render(button_perms): fac.AntdCol( fac.AntdFormItem( fac.AntdInput( - id='job-invoke_target', + id={ + 'type': 'job-form-value', + 'index': 'invoke_target' + }, placeholder='请输入调用目标字符串', style={ 'width': '100%' } ), - id='job-invoke_target-form-item', + id={ + 'type': 'job-form-label', + 'index': 'invoke_target', + 'required': True + }, required=True, label='调用方法', labelCol={ @@ -488,13 +509,20 @@ def render(button_perms): fac.AntdCol( fac.AntdFormItem( fac.AntdInput( - id='job-job_args', + id={ + 'type': 'job-form-value', + 'index': 'job_args' + }, placeholder='请输入位置参数', style={ 'width': '100%' } ), - id='job-job_args-form-item', + id={ + 'type': 'job-form-label', + 'index': 'job_args', + 'required': False + }, label='位置参数', labelCol={ 'span': 6 @@ -508,13 +536,20 @@ def render(button_perms): fac.AntdCol( fac.AntdFormItem( fac.AntdInput( - id='job-job_kwargs', + id={ + 'type': 'job-form-value', + 'index': 'job_kwargs' + }, placeholder='请输入关键字参数', style={ 'width': '100%' } ), - id='job-job_kwargs-form-item', + id={ + 'type': 'job-form-label', + 'index': 'job_kwargs', + 'required': False + }, label='关键字参数', labelCol={ 'span': 6 @@ -533,7 +568,10 @@ def render(button_perms): fac.AntdCol( fac.AntdFormItem( fac.AntdInput( - id='job-cron_expression', + id={ + 'type': 'job-form-value', + 'index': 'cron_expression' + }, placeholder='请输入cron执行表达式', addonAfter=html.Div( [ @@ -550,7 +588,11 @@ def render(button_perms): 'width': '100%' } ), - id='job-cron_expression-form-item', + id={ + 'type': 'job-form-label', + 'index': 'cron_expression', + 'required': True + }, required=True, label='cron表达式', labelCol={ @@ -570,7 +612,10 @@ def render(button_perms): fac.AntdCol( fac.AntdFormItem( fac.AntdRadioGroup( - id='job-misfire_policy', + id={ + 'type': 'job-form-value', + 'index': 'misfire_policy' + }, options=[ { 'label': '立即执行', @@ -589,7 +634,11 @@ def render(button_perms): optionType='button', buttonStyle='solid' ), - id='job-misfire_policy-form-item', + id={ + 'type': 'job-form-label', + 'index': 'misfire_policy', + 'required': False + }, label='执行策略', labelCol={ 'span': 3 @@ -608,7 +657,10 @@ def render(button_perms): fac.AntdCol( fac.AntdFormItem( fac.AntdRadioGroup( - id='job-concurrent', + id={ + 'type': 'job-form-value', + 'index': 'concurrent' + }, options=[ { 'label': '允许', @@ -623,7 +675,11 @@ def render(button_perms): optionType='button', buttonStyle='solid' ), - id='job-concurrent-form-item', + id={ + 'type': 'job-form-label', + 'index': 'concurrent', + 'required': False + }, label='是否并发', labelCol={ 'span': 6 @@ -637,7 +693,10 @@ def render(button_perms): fac.AntdCol( fac.AntdFormItem( fac.AntdRadioGroup( - id='job-status', + id={ + 'type': 'job-form-value', + 'index': 'status' + }, options=[ { 'label': '正常', @@ -650,7 +709,11 @@ def render(button_perms): ], defaultValue='0', ), - id='job-status-form-item', + id={ + 'type': 'job-form-label', + 'index': 'status', + 'required': False + }, label='状态', labelCol={ 'span': 6 @@ -707,10 +770,18 @@ def render(button_perms): [ fac.AntdCol( fac.AntdFormItem( - fac.AntdText(id='job_detail-job_name-text'), + fac.AntdText( + id={ + 'type': 'job_detail-form-value', + 'index': 'job_name' + } + ), label='任务名称', required=True, - id='job_detail-job_name-form-item', + id={ + 'type': 'job_detail-form-label', + 'index': 'job_name' + }, labelCol={ 'span': 8 }, @@ -722,10 +793,18 @@ def render(button_perms): ), fac.AntdCol( fac.AntdFormItem( - fac.AntdText(id='job_detail-job_group-text'), + fac.AntdText( + id={ + 'type': 'job_detail-form-value', + 'index': 'job_group' + } + ), label='任务分组', required=True, - id='job_detail-job_group-form-item', + id={ + 'type': 'job_detail-form-label', + 'index': 'job_group' + }, labelCol={ 'span': 8 }, @@ -742,10 +821,18 @@ def render(button_perms): [ fac.AntdCol( fac.AntdFormItem( - fac.AntdText(id='job_detail-job_executor-text'), + fac.AntdText( + id={ + 'type': 'job_detail-form-value', + 'index': 'job_executor' + } + ), label='任务执行器', required=True, - id='job_detail-job_executor-form-item', + id={ + 'type': 'job_detail-form-label', + 'index': 'job_executor' + }, labelCol={ 'span': 8 }, @@ -757,10 +844,18 @@ def render(button_perms): ), fac.AntdCol( fac.AntdFormItem( - fac.AntdText(id='job_detail-invoke_target-text'), + fac.AntdText( + id={ + 'type': 'job_detail-form-value', + 'index': 'invoke_target' + } + ), label='调用目标函数', required=True, - id='job_detail-invoke_target-form-item', + id={ + 'type': 'job_detail-form-label', + 'index': 'invoke_target' + }, labelCol={ 'span': 8 }, @@ -777,10 +872,18 @@ def render(button_perms): [ fac.AntdCol( fac.AntdFormItem( - fac.AntdText(id='job_detail-job_args-text'), + fac.AntdText( + id={ + 'type': 'job_detail-form-value', + 'index': 'job_args' + } + ), label='位置参数', required=True, - id='job_detail-job_args-form-item', + id={ + 'type': 'job_detail-form-label', + 'index': 'job_args' + }, labelCol={ 'span': 8 }, @@ -792,10 +895,18 @@ def render(button_perms): ), fac.AntdCol( fac.AntdFormItem( - fac.AntdText(id='job_detail-job_kwargs-text'), + fac.AntdText( + id={ + 'type': 'job_detail-form-value', + 'index': 'job_kwargs' + } + ), label='关键字参数', required=True, - id='job_detail-job_kwargs-form-item', + id={ + 'type': 'job_detail-form-label', + 'index': 'job_kwargs' + }, labelCol={ 'span': 8 }, @@ -812,10 +923,18 @@ def render(button_perms): [ fac.AntdCol( fac.AntdFormItem( - fac.AntdText(id='job_detail-cron_expression-text'), + fac.AntdText( + id={ + 'type': 'job_detail-form-value', + 'index': 'cron_expression' + } + ), label='cron表达式', required=True, - id='job_detail-cron_expression-form-item', + id={ + 'type': 'job_detail-form-label', + 'index': 'cron_expression' + }, labelCol={ 'span': 4 }, @@ -831,10 +950,18 @@ def render(button_perms): [ fac.AntdCol( fac.AntdFormItem( - fac.AntdText(id='job_detail-misfire_policy-text'), + fac.AntdText( + id={ + 'type': 'job_detail-form-value', + 'index': 'misfire_policy' + } + ), label='执行策略', required=True, - id='job_detail-misfire_policy-form-item', + id={ + 'type': 'job_detail-form-label', + 'index': 'misfire_policy' + }, labelCol={ 'span': 8 }, @@ -846,10 +973,18 @@ def render(button_perms): ), fac.AntdCol( fac.AntdFormItem( - fac.AntdText(id='job_detail-concurrent-text'), + fac.AntdText( + id={ + 'type': 'job_detail-form-value', + 'index': 'concurrent' + } + ), label='是否并发', required=True, - id='job_detail-concurrent-form-item', + id={ + 'type': 'job_detail-form-label', + 'index': 'concurrent' + }, labelCol={ 'span': 8 }, @@ -866,10 +1001,18 @@ def render(button_perms): [ fac.AntdCol( fac.AntdFormItem( - fac.AntdText(id='job_detail-status-text'), + fac.AntdText( + id={ + 'type': 'job_detail-form-value', + 'index': 'status' + } + ), label='任务状态', required=True, - id='job_detail-status-form-item', + id={ + 'type': 'job_detail-form-label', + 'index': 'status' + }, labelCol={ 'span': 8 }, @@ -881,10 +1024,18 @@ def render(button_perms): ), fac.AntdCol( fac.AntdFormItem( - fac.AntdText(id='job_detail-create_time-text'), + fac.AntdText( + id={ + 'type': 'job_detail-form-value', + 'index': 'create_time' + } + ), label='创建时间', required=True, - id='job_detail-create_time-form-item', + id={ + 'type': 'job_detail-form-label', + 'index': 'create_time' + }, labelCol={ 'span': 8 }, diff --git a/dash-fastapi-frontend/views/monitor/job/job_log.py b/dash-fastapi-frontend/views/monitor/job/job_log.py index a62f2b200c04f5ce2d6bef98b4b9577a95c7de9f..ba5f97d2086da75bc82e64c85e55d90880e0691d 100644 --- a/dash-fastapi-frontend/views/monitor/job/job_log.py +++ b/dash-fastapi-frontend/views/monitor/job/job_log.py @@ -5,7 +5,6 @@ import callbacks.monitor_c.job_c.job_log_c def render(button_perms): - return [ dcc.Store(id='job_log-button-perms-container', data=button_perms), # 用于导出成功后重置dcc.Download的状态,防止多次下载文件 @@ -311,7 +310,7 @@ def render(button_perms): gutter=5 ), - # 任务调度日志明细modal + # 任务调度日志明细modal,表单项id使用字典类型,index与后端数据库字段一一对应 fac.AntdModal( [ fac.AntdForm( @@ -320,10 +319,18 @@ def render(button_perms): [ fac.AntdCol( fac.AntdFormItem( - fac.AntdText(id='job_log-job_name-text'), + fac.AntdText( + id={ + 'type': 'job_log-form-value', + 'index': 'job_name' + } + ), label='任务名称', required=True, - id='job_log-job_name-form-item', + id={ + 'type': 'job_log-form-label', + 'index': 'job_name' + }, labelCol={ 'span': 8 }, @@ -335,10 +342,18 @@ def render(button_perms): ), fac.AntdCol( fac.AntdFormItem( - fac.AntdText(id='job_log-job_group-text'), + fac.AntdText( + id={ + 'type': 'job_log-form-value', + 'index': 'job_group' + } + ), label='任务分组', required=True, - id='job_log-job_group-form-item', + id={ + 'type': 'job_log-form-label', + 'index': 'job_group' + }, labelCol={ 'span': 8 }, @@ -355,10 +370,18 @@ def render(button_perms): [ fac.AntdCol( fac.AntdFormItem( - fac.AntdText(id='job_log-job_executor-text'), + fac.AntdText( + id={ + 'type': 'job_log-form-value', + 'index': 'job_executor' + } + ), label='任务执行器', required=True, - id='job_log-job_executor-form-item', + id={ + 'type': 'job_log-form-label', + 'index': 'job_executor' + }, labelCol={ 'span': 8 }, @@ -370,10 +393,18 @@ def render(button_perms): ), fac.AntdCol( fac.AntdFormItem( - fac.AntdText(id='job_log-invoke_target-text'), + fac.AntdText( + id={ + 'type': 'job_log-form-value', + 'index': 'invoke_target' + } + ), label='调用目标字符串', required=True, - id='job_log-invoke_target-form-item', + id={ + 'type': 'job_log-form-label', + 'index': 'invoke_target' + }, labelCol={ 'span': 8 }, @@ -390,10 +421,18 @@ def render(button_perms): [ fac.AntdCol( fac.AntdFormItem( - fac.AntdText(id='job_log-job_args-text'), + fac.AntdText( + id={ + 'type': 'job_log-form-value', + 'index': 'job_args' + } + ), label='位置参数', required=True, - id='job_log-job_args-form-item', + id={ + 'type': 'job_log-form-label', + 'index': 'job_args' + }, labelCol={ 'span': 8 }, @@ -405,10 +444,18 @@ def render(button_perms): ), fac.AntdCol( fac.AntdFormItem( - fac.AntdText(id='job_log-job_kwargs-text'), + fac.AntdText( + id={ + 'type': 'job_log-form-value', + 'index': 'job_kwargs' + } + ), label='关键字参数', required=True, - id='job_log-job_kwargs-form-item', + id={ + 'type': 'job_log-form-label', + 'index': 'job_kwargs' + }, labelCol={ 'span': 8 }, @@ -425,10 +472,18 @@ def render(button_perms): [ fac.AntdCol( fac.AntdFormItem( - fac.AntdText(id='job_log-job_trigger-text'), + fac.AntdText( + id={ + 'type': 'job_log-form-value', + 'index': 'job_trigger' + } + ), label='任务触发器', required=True, - id='job_log-job_trigger-form-item', + id={ + 'type': 'job_log-form-label', + 'index': 'job_trigger' + }, labelCol={ 'span': 4 }, @@ -444,10 +499,18 @@ def render(button_perms): [ fac.AntdCol( fac.AntdFormItem( - fac.AntdText(id='job_log-job_message-text'), + fac.AntdText( + id={ + 'type': 'job_log-form-value', + 'index': 'job_message' + } + ), label='日志信息', required=True, - id='job_log-job_message-form-item', + id={ + 'type': 'job_log-form-label', + 'index': 'job_message' + }, labelCol={ 'span': 4 }, @@ -463,10 +526,18 @@ def render(button_perms): [ fac.AntdCol( fac.AntdFormItem( - fac.AntdText(id='job_log-status-text'), + fac.AntdText( + id={ + 'type': 'job_log-form-value', + 'index': 'status' + } + ), label='执行状态', required=True, - id='job_log-status-form-item', + id={ + 'type': 'job_log-form-label', + 'index': 'status' + }, labelCol={ 'span': 8 }, @@ -478,10 +549,18 @@ def render(button_perms): ), fac.AntdCol( fac.AntdFormItem( - fac.AntdText(id='job_log-create_time-text'), + fac.AntdText( + id={ + 'type': 'job_log-form-value', + 'index': 'create_time' + } + ), label='执行时间', required=True, - id='job_log-create_time-form-item', + id={ + 'type': 'job_log-form-label', + 'index': 'create_time' + }, labelCol={ 'span': 8 }, @@ -498,10 +577,18 @@ def render(button_perms): [ fac.AntdCol( fac.AntdFormItem( - fac.AntdText(id='job_log-exception_info-text'), + fac.AntdText( + id={ + 'type': 'job_log-form-value', + 'index': 'exception_info' + } + ), label='异常信息', required=True, - id='job_log-exception_info-form-item', + id={ + 'type': 'job_log-form-label', + 'index': 'exception_info' + }, labelCol={ 'span': 4 }, diff --git a/dash-fastapi-frontend/views/monitor/operlog/__init__.py b/dash-fastapi-frontend/views/monitor/operlog/__init__.py index 7e41ce51805de37f9c4900c002033ad46e864a99..1ee38e09230b26e8d9018f62b1d461d508218fa1 100644 --- a/dash-fastapi-frontend/views/monitor/operlog/__init__.py +++ b/dash-fastapi-frontend/views/monitor/operlog/__init__.py @@ -396,10 +396,18 @@ def render(button_perms): [ fac.AntdCol( fac.AntdFormItem( - fac.AntdText(id='operation_log-title-text'), + fac.AntdText( + id={ + 'type': 'operation_log-form-value', + 'index': 'title' + } + ), label='操作模块', required=True, - id='operation_log-title-form-item', + id={ + 'type': 'operation_log-form-label', + 'index': 'title' + }, labelCol={ 'span': 8 }, @@ -411,10 +419,18 @@ def render(button_perms): ), fac.AntdCol( fac.AntdFormItem( - fac.AntdText(id='operation_log-oper_url-text'), + fac.AntdText( + id={ + 'type': 'operation_log-form-value', + 'index': 'oper_url' + } + ), label='请求地址', required=True, - id='operation_log-oper_url-form-item', + id={ + 'type': 'operation_log-form-label', + 'index': 'oper_url' + }, labelCol={ 'span': 8 }, @@ -431,10 +447,18 @@ def render(button_perms): [ fac.AntdCol( fac.AntdFormItem( - fac.AntdText(id='operation_log-login_info-text'), + fac.AntdText( + id={ + 'type': 'operation_log-form-value', + 'index': 'login_info' + } + ), label='登录信息', required=True, - id='operation_log-login_info-form-item', + id={ + 'type': 'operation_log-form-label', + 'index': 'login_info' + }, labelCol={ 'span': 8 }, @@ -446,10 +470,18 @@ def render(button_perms): ), fac.AntdCol( fac.AntdFormItem( - fac.AntdText(id='operation_log-request_method-text'), + fac.AntdText( + id={ + 'type': 'operation_log-form-value', + 'index': 'request_method' + } + ), label='请求方式', required=True, - id='operation_log-request_method-form-item', + id={ + 'type': 'operation_log-form-label', + 'index': 'request_method' + }, labelCol={ 'span': 8 }, @@ -466,10 +498,18 @@ def render(button_perms): [ fac.AntdCol( fac.AntdFormItem( - fac.AntdText(id='operation_log-method-text'), + fac.AntdText( + id={ + 'type': 'operation_log-form-value', + 'index': 'method' + } + ), label='操作方法', required=True, - id='operation_log-method-form-item', + id={ + 'type': 'operation_log-form-label', + 'index': 'method' + }, labelCol={ 'span': 4 }, @@ -485,10 +525,18 @@ def render(button_perms): [ fac.AntdCol( fac.AntdFormItem( - fac.AntdText(id='operation_log-oper_param-text'), + fac.AntdText( + id={ + 'type': 'operation_log-form-value', + 'index': 'oper_param' + } + ), label='请求参数', required=True, - id='operation_log-oper_param-form-item', + id={ + 'type': 'operation_log-form-label', + 'index': 'oper_param' + }, labelCol={ 'span': 4 }, @@ -504,10 +552,18 @@ def render(button_perms): [ fac.AntdCol( fac.AntdFormItem( - fac.AntdText(id='operation_log-json_result-text'), + fac.AntdText( + id={ + 'type': 'operation_log-form-value', + 'index': 'json_result' + } + ), label='返回参数', required=True, - id='operation_log-json_result-form-item', + id={ + 'type': 'operation_log-form-label', + 'index': 'json_result' + }, labelCol={ 'span': 4 }, @@ -523,10 +579,18 @@ def render(button_perms): [ fac.AntdCol( fac.AntdFormItem( - fac.AntdText(id='operation_log-status-text'), + fac.AntdText( + id={ + 'type': 'operation_log-form-value', + 'index': 'status' + } + ), label='操作状态', required=True, - id='operation_log-status-form-item', + id={ + 'type': 'operation_log-form-label', + 'index': 'status' + }, labelCol={ 'span': 12 }, @@ -538,10 +602,18 @@ def render(button_perms): ), fac.AntdCol( fac.AntdFormItem( - fac.AntdText(id='operation_log-cost_time-text'), + fac.AntdText( + id={ + 'type': 'operation_log-form-value', + 'index': 'cost_time' + } + ), label='消耗时间', required=True, - id='operation_log-cost_time-form-item', + id={ + 'type': 'operation_log-form-label', + 'index': 'cost_time' + }, labelCol={ 'span': 12 }, @@ -553,10 +625,18 @@ def render(button_perms): ), fac.AntdCol( fac.AntdFormItem( - fac.AntdText(id='operation_log-oper_time-text'), + fac.AntdText( + id={ + 'type': 'operation_log-form-value', + 'index': 'oper_time' + } + ), label='操作时间', required=True, - id='operation_log-oper_time-form-item', + id={ + 'type': 'operation_log-form-label', + 'index': 'oper_time' + }, labelCol={ 'span': 8 }, diff --git a/dash-fastapi-frontend/views/system/config/__init__.py b/dash-fastapi-frontend/views/system/config/__init__.py index c6aabb0c1f9216483da84ee925db0eeba18a26c5..9a3457507f1e526205e535313f6e33ebf671de1e 100644 --- a/dash-fastapi-frontend/views/system/config/__init__.py +++ b/dash-fastapi-frontend/views/system/config/__init__.py @@ -393,7 +393,10 @@ def render(button_perms): fac.AntdCol( fac.AntdFormItem( fac.AntdInput( - id='config-config_name', + id={ + 'type': 'config-form-value', + 'index': 'config_name' + }, placeholder='请输入参数名称', allowClear=True, style={ @@ -402,7 +405,11 @@ def render(button_perms): ), label='参数名称', required=True, - id='config-config_name-form-item' + id={ + 'type': 'config-form-label', + 'index': 'config_name', + 'required': True + } ), span=24 ), @@ -413,7 +420,10 @@ def render(button_perms): fac.AntdCol( fac.AntdFormItem( fac.AntdInput( - id='config-config_key', + id={ + 'type': 'config-form-value', + 'index': 'config_key' + }, placeholder='请输入参数键名', allowClear=True, style={ @@ -422,7 +432,11 @@ def render(button_perms): ), label='参数键名', required=True, - id='config-config_key-form-item' + id={ + 'type': 'config-form-label', + 'index': 'config_key', + 'required': True + } ), span=24 ), @@ -433,7 +447,10 @@ def render(button_perms): fac.AntdCol( fac.AntdFormItem( fac.AntdInput( - id='config-config_value', + id={ + 'type': 'config-form-value', + 'index': 'config_value' + }, placeholder='请输入参数键值', allowClear=True, style={ @@ -442,7 +459,11 @@ def render(button_perms): ), label='参数键值', required=True, - id='config-config_value-form-item' + id={ + 'type': 'config-form-label', + 'index': 'config_value', + 'required': True + } ), span=24 ), @@ -453,7 +474,10 @@ def render(button_perms): fac.AntdCol( fac.AntdFormItem( fac.AntdRadioGroup( - id='config-config_type', + id={ + 'type': 'config-form-value', + 'index': 'config_type' + }, options=[ { 'label': '是', @@ -470,7 +494,11 @@ def render(button_perms): } ), label='系统内置', - id='config-config_type-form-item' + id={ + 'type': 'config-form-label', + 'index': 'config_type', + 'required': False + } ), span=24 ), @@ -481,7 +509,10 @@ def render(button_perms): fac.AntdCol( fac.AntdFormItem( fac.AntdInput( - id='config-remark', + id={ + 'type': 'config-form-value', + 'index': 'remark' + }, placeholder='请输入内容', allowClear=True, mode='text-area', @@ -490,7 +521,11 @@ def render(button_perms): } ), label='备注', - id='config-remark-form-item' + id={ + 'type': 'config-form-label', + 'index': 'remark', + 'required': False + } ), span=24 ), diff --git a/dash-fastapi-frontend/views/system/dept/__init__.py b/dash-fastapi-frontend/views/system/dept/__init__.py index b5d2a299111f1c27a06f91faee7da1719d4427c9..bc8de1b4b673d7b0da5aadf076c1023395f14a30 100644 --- a/dash-fastapi-frontend/views/system/dept/__init__.py +++ b/dash-fastapi-frontend/views/system/dept/__init__.py @@ -329,7 +329,10 @@ def render(button_perms): [ fac.AntdFormItem( fac.AntdTreeSelect( - id='dept-parent_id', + id={ + 'type': 'dept-form-value', + 'index': 'parent_id' + }, placeholder='请选择上级部门', treeData=[], treeNodeFilterProp='title', @@ -339,7 +342,11 @@ def render(button_perms): ), label='上级部门', required=True, - id='dept-parent_id-form-item', + id={ + 'type': 'dept-form-label', + 'index': 'parent_id', + 'required': True + }, labelCol={ 'span': 4 }, @@ -360,7 +367,10 @@ def render(button_perms): fac.AntdCol( fac.AntdFormItem( fac.AntdInput( - id='dept-dept_name', + id={ + 'type': 'dept-form-value', + 'index': 'dept_name' + }, placeholder='请输入部门名称', allowClear=True, style={ @@ -369,14 +379,21 @@ def render(button_perms): ), label='部门名称', required=True, - id='dept-dept_name-form-item' + id={ + 'type': 'dept-form-label', + 'index': 'dept_name', + 'required': True + } ), span=12 ), fac.AntdCol( fac.AntdFormItem( fac.AntdInputNumber( - id='dept-order_num', + id={ + 'type': 'dept-form-value', + 'index': 'order_num' + }, min=0, style={ 'width': '100%' @@ -384,7 +401,11 @@ def render(button_perms): ), label='显示顺序', required=True, - id='dept-order_num-form-item' + id={ + 'type': 'dept-form-label', + 'index': 'order_num', + 'required': True + } ), span=12 ) @@ -396,7 +417,10 @@ def render(button_perms): fac.AntdCol( fac.AntdFormItem( fac.AntdInput( - id='dept-leader', + id={ + 'type': 'dept-form-value', + 'index': 'leader' + }, placeholder='请输入负责人', allowClear=True, style={ @@ -404,14 +428,21 @@ def render(button_perms): } ), label='负责人', - id='dept-leader-form-item' + id={ + 'type': 'dept-form-label', + 'index': 'leader', + 'required': False + } ), span=12 ), fac.AntdCol( fac.AntdFormItem( fac.AntdInput( - id='dept-phone', + id={ + 'type': 'dept-form-value', + 'index': 'phone' + }, placeholder='请输入联系电话', allowClear=True, style={ @@ -419,7 +450,11 @@ def render(button_perms): } ), label='联系电话', - id='dept-phone-form-item' + id={ + 'type': 'dept-form-label', + 'index': 'phone', + 'required': False + } ), span=12 ), @@ -431,7 +466,10 @@ def render(button_perms): fac.AntdCol( fac.AntdFormItem( fac.AntdInput( - id='dept-email', + id={ + 'type': 'dept-form-value', + 'index': 'email' + }, placeholder='请输入邮箱', allowClear=True, style={ @@ -439,14 +477,21 @@ def render(button_perms): } ), label='邮箱', - id='dept-email-form-item' + id={ + 'type': 'dept-form-label', + 'index': 'email', + 'required': False + } ), span=12 ), fac.AntdCol( fac.AntdFormItem( fac.AntdRadioGroup( - id='dept-status', + id={ + 'type': 'dept-form-value', + 'index': 'status' + }, options=[ { 'label': '正常', @@ -463,7 +508,11 @@ def render(button_perms): } ), label='部门状态', - id='dept-status-form-item' + id={ + 'type': 'dept-form-label', + 'index': 'status', + 'required': False + } ), span=12 ), diff --git a/dash-fastapi-frontend/views/system/dict/__init__.py b/dash-fastapi-frontend/views/system/dict/__init__.py index a3b0a1f581cb085739d3c9377f7eb84e6299e5ae..608f59ee035c4a89c78d092a150f97118960663d 100644 --- a/dash-fastapi-frontend/views/system/dict/__init__.py +++ b/dash-fastapi-frontend/views/system/dict/__init__.py @@ -394,7 +394,10 @@ def render(button_perms): fac.AntdCol( fac.AntdFormItem( fac.AntdInput( - id='dict_type-dict_name', + id={ + 'type': 'dict_type-form-value', + 'index': 'dict_name' + }, placeholder='请输入字典名称', allowClear=True, style={ @@ -403,7 +406,11 @@ def render(button_perms): ), label='字典名称', required=True, - id='dict_type-dict_name-form-item' + id={ + 'type': 'dict_type-form-label', + 'index': 'dict_name', + 'required': True + } ), span=24 ), @@ -414,7 +421,10 @@ def render(button_perms): fac.AntdCol( fac.AntdFormItem( fac.AntdInput( - id='dict_type-dict_type', + id={ + 'type': 'dict_type-form-value', + 'index': 'dict_type' + }, placeholder='请输入字典类型', allowClear=True, style={ @@ -423,7 +433,11 @@ def render(button_perms): ), label='字典类型', required=True, - id='dict_type-dict_type-form-item' + id={ + 'type': 'dict_type-form-label', + 'index': 'dict_type', + 'required': True + } ), span=24 ), @@ -434,7 +448,10 @@ def render(button_perms): fac.AntdCol( fac.AntdFormItem( fac.AntdRadioGroup( - id='dict_type-status', + id={ + 'type': 'dict_type-form-value', + 'index': 'status' + }, options=[ { 'label': '正常', @@ -451,7 +468,11 @@ def render(button_perms): } ), label='状态', - id='dict_type-status-form-item' + id={ + 'type': 'dict_type-form-label', + 'index': 'status', + 'required': False + } ), span=24 ), @@ -462,7 +483,10 @@ def render(button_perms): fac.AntdCol( fac.AntdFormItem( fac.AntdInput( - id='dict_type-remark', + id={ + 'type': 'dict_type-form-value', + 'index': 'remark' + }, placeholder='请输入内容', allowClear=True, mode='text-area', @@ -471,7 +495,11 @@ def render(button_perms): } ), label='备注', - id='dict_type-remark-form-item' + id={ + 'type': 'dict_type-form-label', + 'index': 'remark', + 'required': False + } ), span=24 ), diff --git a/dash-fastapi-frontend/views/system/dict/dict_data.py b/dash-fastapi-frontend/views/system/dict/dict_data.py index 57aa97ef4b649c1134c7de6e5f0a07c2e1ef9850..6352390e0b91c00ab6ec492111fd8a8d6d285110 100644 --- a/dash-fastapi-frontend/views/system/dict/dict_data.py +++ b/dash-fastapi-frontend/views/system/dict/dict_data.py @@ -333,7 +333,10 @@ def render(button_perms): fac.AntdCol( fac.AntdFormItem( fac.AntdInput( - id='dict_data-dict_type', + id={ + 'type': 'dict_data-form-value', + 'index': 'dict_type' + }, placeholder='请输入字典类型', disabled=True, style={ @@ -341,7 +344,11 @@ def render(button_perms): } ), label='字典类型', - id='dict_data-dict_type-form-item' + id={ + 'type': 'dict_data-form-label', + 'index': 'dict_type', + 'required': False + } ), span=24 ), @@ -352,7 +359,10 @@ def render(button_perms): fac.AntdCol( fac.AntdFormItem( fac.AntdInput( - id='dict_data-dict_label', + id={ + 'type': 'dict_data-form-value', + 'index': 'dict_label' + }, placeholder='请输入数据标签', allowClear=True, style={ @@ -361,7 +371,11 @@ def render(button_perms): ), label='数据标签', required=True, - id='dict_data-dict_label-form-item' + id={ + 'type': 'dict_data-form-label', + 'index': 'dict_label', + 'required': True + } ), span=24 ), @@ -372,7 +386,10 @@ def render(button_perms): fac.AntdCol( fac.AntdFormItem( fac.AntdInput( - id='dict_data-dict_value', + id={ + 'type': 'dict_data-form-value', + 'index': 'dict_value' + }, placeholder='请输入数据键值', allowClear=True, style={ @@ -381,7 +398,11 @@ def render(button_perms): ), label='数据键值', required=True, - id='dict_data-dict_value-form-item' + id={ + 'type': 'dict_data-form-label', + 'index': 'dict_value', + 'required': True + } ), span=24 ), @@ -392,7 +413,10 @@ def render(button_perms): fac.AntdCol( fac.AntdFormItem( fac.AntdInput( - id='dict_data-css_class', + id={ + 'type': 'dict_data-form-value', + 'index': 'css_class' + }, placeholder='请输入样式属性', allowClear=True, style={ @@ -400,7 +424,11 @@ def render(button_perms): } ), label='样式属性', - id='dict_data-css_class-form-item' + id={ + 'type': 'dict_data-form-label', + 'index': 'css_class', + 'required': False + } ), span=24 ), @@ -411,7 +439,10 @@ def render(button_perms): fac.AntdCol( fac.AntdFormItem( fac.AntdInputNumber( - id='dict_data-dict_sort', + id={ + 'type': 'dict_data-form-value', + 'index': 'dict_sort' + }, defaultValue=0, min=0, style={ @@ -420,7 +451,11 @@ def render(button_perms): ), label='显示排序', required=True, - id='dict_data-dict_sort-form-item' + id={ + 'type': 'dict_data-form-label', + 'index': 'dict_sort', + 'required': True + } ), span=24 ), @@ -431,7 +466,10 @@ def render(button_perms): fac.AntdCol( fac.AntdFormItem( fac.AntdSelect( - id='dict_data-list_class', + id={ + 'type': 'dict_data-form-value', + 'index': 'list_class' + }, placeholder='回显样式', options=[ { @@ -464,7 +502,11 @@ def render(button_perms): } ), label='回显样式', - id='dict_data-list_class-form-item' + id={ + 'type': 'dict_data-form-label', + 'index': 'list_class', + 'required': False + } ), span=24 ), @@ -475,7 +517,10 @@ def render(button_perms): fac.AntdCol( fac.AntdFormItem( fac.AntdRadioGroup( - id='dict_data-status', + id={ + 'type': 'dict_data-form-value', + 'index': 'status' + }, options=[ { 'label': '正常', @@ -492,7 +537,11 @@ def render(button_perms): } ), label='状态', - id='dict_data-status-form-item' + id={ + 'type': 'dict_data-form-label', + 'index': 'status', + 'required': False + } ), span=24 ), @@ -503,7 +552,10 @@ def render(button_perms): fac.AntdCol( fac.AntdFormItem( fac.AntdInput( - id='dict_data-remark', + id={ + 'type': 'dict_data-form-value', + 'index': 'remark' + }, placeholder='请输入内容', allowClear=True, mode='text-area', @@ -512,7 +564,11 @@ def render(button_perms): } ), label='备注', - id='dict_data-remark-form-item' + id={ + 'type': 'dict_data-form-label', + 'index': 'remark', + 'required': False + } ), span=24 ), diff --git a/dash-fastapi-frontend/views/system/post/__init__.py b/dash-fastapi-frontend/views/system/post/__init__.py index a3110e890be5c7b2b44bf40c380353b7d65873ef..af668e8c10aa69da5ed50eaa816fb02b1cc4d1fd 100644 --- a/dash-fastapi-frontend/views/system/post/__init__.py +++ b/dash-fastapi-frontend/views/system/post/__init__.py @@ -360,7 +360,10 @@ def render(button_perms): [ fac.AntdFormItem( fac.AntdInput( - id='post-post_name', + id={ + 'type': 'post-form-value', + 'index': 'post_name' + }, placeholder='请输入岗位名称', allowClear=True, style={ @@ -369,11 +372,18 @@ def render(button_perms): ), label='岗位名称', required=True, - id='post-post_name-form-item' + id={ + 'type': 'post-form-label', + 'index': 'post_name', + 'required': True + } ), fac.AntdFormItem( fac.AntdInput( - id='post-post_code', + id={ + 'type': 'post-form-value', + 'index': 'post_code' + }, placeholder='请输入岗位编码', allowClear=True, style={ @@ -382,11 +392,18 @@ def render(button_perms): ), label='岗位编码', required=True, - id='post-post_code-form-item' + id={ + 'type': 'post-form-label', + 'index': 'post_code', + 'required': True + } ), fac.AntdFormItem( fac.AntdInputNumber( - id='post-post_sort', + id={ + 'type': 'post-form-value', + 'index': 'post_sort' + }, defaultValue=0, min=0, style={ @@ -395,11 +412,18 @@ def render(button_perms): ), label='岗位顺序', required=True, - id='post-post_sort-form-item' + id={ + 'type': 'post-form-label', + 'index': 'post_sort', + 'required': True + } ), fac.AntdFormItem( fac.AntdRadioGroup( - id='post-status', + id={ + 'type': 'post-form-value', + 'index': 'status' + }, options=[ { 'label': '正常', @@ -416,11 +440,18 @@ def render(button_perms): } ), label='岗位状态', - id='post-status-form-item' + id={ + 'type': 'post-form-label', + 'index': 'status', + 'required': False + } ), fac.AntdFormItem( fac.AntdInput( - id='post-remark', + id={ + 'type': 'post-form-value', + 'index': 'remark' + }, placeholder='请输入内容', allowClear=True, mode='text-area', @@ -429,7 +460,11 @@ def render(button_perms): } ), label='备注', - id='post-remark-form-item' + id={ + 'type': 'post-form-label', + 'index': 'remark', + 'required': False + } ), ], labelCol={ diff --git a/dash-fastapi-frontend/views/system/role/__init__.py b/dash-fastapi-frontend/views/system/role/__init__.py index 073ff9b96526ff8d54cd470a2f2de4f9c1d810c3..212fce1e12219eaa28fc8c2dcf93adf0dba10997 100644 --- a/dash-fastapi-frontend/views/system/role/__init__.py +++ b/dash-fastapi-frontend/views/system/role/__init__.py @@ -21,9 +21,9 @@ def render(button_perms): total = table_info['data']['total'] for item in table_data: if item['status'] == '0': - item['status'] = dict(checked=True) + item['status'] = dict(checked=True, disabled=item['role_id'] == 1) else: - item['status'] = dict(checked=False) + item['status'] = dict(checked=False, disabled=item['role_id'] == 1) item['key'] = str(item['role_id']) if item['role_id'] == 1: item['operation'] = [] @@ -409,6 +409,7 @@ def render(button_perms): }, { 'title': '操作', + 'width': 180, 'dataIndex': 'operation', } ], @@ -448,7 +449,11 @@ def render(button_perms): [ fac.AntdFormItem( fac.AntdInput( - id='role-role_name', + id={ + 'type': 'role-form-value', + 'index': 'role_name', + 'required': True + }, placeholder='请输入角色名称', allowClear=True, style={ @@ -457,7 +462,11 @@ def render(button_perms): ), label='角色名称', required=True, - id='role-role_name-form-item', + id={ + 'type': 'role-form-label', + 'index': 'role_name', + 'required': True + }, labelCol={ 'span': 6 }, @@ -467,7 +476,11 @@ def render(button_perms): ), fac.AntdFormItem( fac.AntdInput( - id='role-role_key', + id={ + 'type': 'role-form-value', + 'index': 'role_key', + 'required': True + }, placeholder='请输入权限字符', allowClear=True, style={ @@ -486,7 +499,11 @@ def render(button_perms): ] ), required=True, - id='role-role_Key-form-item', + id={ + 'type': 'role-form-label', + 'index': 'role_key', + 'required': True + }, labelCol={ 'span': 6 }, @@ -496,7 +513,11 @@ def render(button_perms): ), fac.AntdFormItem( fac.AntdInputNumber( - id='role-role_sort', + id={ + 'type': 'role-form-value', + 'index': 'role_sort', + 'required': True + }, placeholder='请输入角色顺序', defaultValue=0, min=0, @@ -506,7 +527,11 @@ def render(button_perms): ), label='角色顺序', required=True, - id='role-role_sort-form-item', + id={ + 'type': 'role-form-label', + 'index': 'role_sort', + 'required': True + }, labelCol={ 'span': 6 }, @@ -516,7 +541,11 @@ def render(button_perms): ), fac.AntdFormItem( fac.AntdRadioGroup( - id='role-status', + id={ + 'type': 'role-form-value', + 'index': 'status', + 'required': False + }, options=[ { 'label': '正常', @@ -532,7 +561,11 @@ def render(button_perms): } ), label='状态', - id='role-status-form-item', + id={ + 'type': 'role-form-label', + 'index': 'status', + 'required': False + }, labelCol={ 'span': 6 }, @@ -607,7 +640,11 @@ def render(button_perms): ), fac.AntdFormItem( fac.AntdInput( - id='role-remark', + id={ + 'type': 'role-form-value', + 'index': 'remark', + 'required': False + }, placeholder='请输入内容', allowClear=True, mode='text-area', @@ -616,7 +653,11 @@ def render(button_perms): } ), label='备注', - id='role-remark-form-item', + id={ + 'type': 'role-form-label', + 'index': 'remark', + 'required': False + }, labelCol={ 'span': 6 }, diff --git a/dash-fastapi-frontend/views/system/user/__init__.py b/dash-fastapi-frontend/views/system/user/__init__.py index 498ba1637c887d0f71fcc6fae4e02234b0cbf88c..34651a886ac670935e9a2e7b58af2c096c9e4193 100644 --- a/dash-fastapi-frontend/views/system/user/__init__.py +++ b/dash-fastapi-frontend/views/system/user/__init__.py @@ -449,7 +449,10 @@ def render(button_perms): [ fac.AntdFormItem( fac.AntdInput( - id='user-add-nick_name', + id={ + 'type': 'user_add-form-value', + 'index': 'nick_name' + }, placeholder='请输入用户昵称', allowClear=True, style={ @@ -458,11 +461,18 @@ def render(button_perms): ), label='用户昵称', required=True, - id='user-add-nick_name-form-item' + id={ + 'type': 'user_add-form-label', + 'index': 'nick_name', + 'required': True + } ), fac.AntdFormItem( fac.AntdTreeSelect( - id='user-add-dept_id', + id={ + 'type': 'user_add-form-value', + 'index': 'dept_id' + }, placeholder='请选择归属部门', treeData=[], treeNodeFilterProp='title', @@ -471,7 +481,11 @@ def render(button_perms): } ), label='归属部门', - id='user-add-dept_id-form-item', + id={ + 'type': 'user_add-form-label', + 'index': 'dept_id', + 'required': False + }, labelCol={ 'offset': 1 }, @@ -483,7 +497,10 @@ def render(button_perms): [ fac.AntdFormItem( fac.AntdInput( - id='user-add-phone_number', + id={ + 'type': 'user_add-form-value', + 'index': 'phonenumber' + }, placeholder='请输入手机号码', allowClear=True, style={ @@ -491,14 +508,21 @@ def render(button_perms): } ), label='手机号码', - id='user-add-phone_number-form-item', + id={ + 'type': 'user_add-form-label', + 'index': 'phonenumber', + 'required': False + }, labelCol={ 'offset': 1 }, ), fac.AntdFormItem( fac.AntdInput( - id='user-add-email', + id={ + 'type': 'user_add-form-value', + 'index': 'email' + }, placeholder='请输入邮箱', allowClear=True, style={ @@ -506,7 +530,11 @@ def render(button_perms): } ), label='邮箱', - id='user-add-email-form-item', + id={ + 'type': 'user_add-form-label', + 'index': 'email', + 'required': False + }, labelCol={ 'offset': 5 }, @@ -518,7 +546,10 @@ def render(button_perms): [ fac.AntdFormItem( fac.AntdInput( - id='user-add-user_name', + id={ + 'type': 'user_add-form-value', + 'index': 'user_name' + }, placeholder='请输入用户名称', allowClear=True, style={ @@ -527,11 +558,18 @@ def render(button_perms): ), label='用户名称', required=True, - id='user-add-user_name-form-item' + id={ + 'type': 'user_add-form-label', + 'index': 'user_name', + 'required': True + } ), fac.AntdFormItem( fac.AntdInput( - id='user-add-password', + id={ + 'type': 'user_add-form-value', + 'index': 'password' + }, placeholder='请输入密码', mode='password', passwordUseMd5=True, @@ -541,7 +579,11 @@ def render(button_perms): ), label='用户密码', required=True, - id='user-add-password-form-item' + id={ + 'type': 'user_add-form-label', + 'index': 'password', + 'required': True + } ), ], size="middle" @@ -550,7 +592,10 @@ def render(button_perms): [ fac.AntdFormItem( fac.AntdSelect( - id='user-add-sex', + id={ + 'type': 'user_add-form-value', + 'index': 'sex' + }, placeholder='请选择性别', options=[ { @@ -571,14 +616,21 @@ def render(button_perms): } ), label='用户性别', - id='user-add-sex-form-item', + id={ + 'type': 'user_add-form-label', + 'index': 'sex', + 'required': False + }, labelCol={ 'offset': 1 }, ), fac.AntdFormItem( fac.AntdRadioGroup( - id='user-add-status', + id={ + 'type': 'user_add-form-value', + 'index': 'status' + }, options=[ { 'label': '正常', @@ -595,7 +647,11 @@ def render(button_perms): } ), label='用户状态', - id='user-add-status-form-item', + id={ + 'type': 'user_add-form-label', + 'index': 'status', + 'required': False + }, labelCol={ 'offset': 2 }, @@ -646,7 +702,10 @@ def render(button_perms): [ fac.AntdFormItem( fac.AntdInput( - id='user-add-remark', + id={ + 'type': 'user_add-form-value', + 'index': 'remark' + }, placeholder='请输入内容', allowClear=True, mode='text-area', @@ -655,7 +714,11 @@ def render(button_perms): } ), label='备注', - id='user-add-remark-form-item', + id={ + 'type': 'user_add-form-label', + 'index': 'remark', + 'required': False + }, labelCol={ 'offset': 2 }, @@ -682,7 +745,10 @@ def render(button_perms): [ fac.AntdFormItem( fac.AntdInput( - id='user-edit-nick_name', + id={ + 'type': 'user_edit-form-value', + 'index': 'nick_name' + }, placeholder='请输入用户昵称', allowClear=True, style={ @@ -691,11 +757,18 @@ def render(button_perms): ), label='用户昵称', required=True, - id='user-edit-nick_name-form-item' + id={ + 'type': 'user_edit-form-label', + 'index': 'nick_name', + 'required': True + } ), fac.AntdFormItem( fac.AntdTreeSelect( - id='user-edit-dept_id', + id={ + 'type': 'user_edit-form-value', + 'index': 'dept_id' + }, placeholder='请选择归属部门', treeData=[], treeNodeFilterProp='title', @@ -704,7 +777,11 @@ def render(button_perms): } ), label='归属部门', - id='user-edit-dept_id-form-item' + id={ + 'type': 'user_edit-form-label', + 'index': 'dept_id', + 'required': False + } ), ], size="middle" @@ -713,7 +790,10 @@ def render(button_perms): [ fac.AntdFormItem( fac.AntdInput( - id='user-edit-phone_number', + id={ + 'type': 'user_edit-form-value', + 'index': 'phonenumber' + }, placeholder='请输入手机号码', allowClear=True, style={ @@ -721,14 +801,21 @@ def render(button_perms): } ), label='手机号码', - id='user-edit-phone_number-form-item', + id={ + 'type': 'user_edit-form-label', + 'index': 'phonenumber', + 'required': False + }, labelCol={ 'offset': 1 }, ), fac.AntdFormItem( fac.AntdInput( - id='user-edit-email', + id={ + 'type': 'user_edit-form-value', + 'index': 'email' + }, placeholder='请输入邮箱', allowClear=True, style={ @@ -736,7 +823,11 @@ def render(button_perms): } ), label='邮箱', - id='user-edit-email-form-item', + id={ + 'type': 'user_edit-form-label', + 'index': 'email', + 'required': False + }, labelCol={ 'offset': 4 }, @@ -748,7 +839,10 @@ def render(button_perms): [ fac.AntdFormItem( fac.AntdSelect( - id='user-edit-sex', + id={ + 'type': 'user_edit-form-value', + 'index': 'sex' + }, placeholder='请选择性别', options=[ { @@ -769,14 +863,21 @@ def render(button_perms): } ), label='用户性别', - id='user-edit-sex-form-item', + id={ + 'type': 'user_edit-form-label', + 'index': 'sex', + 'required': False + }, labelCol={ 'offset': 1 }, ), fac.AntdFormItem( fac.AntdRadioGroup( - id='user-edit-status', + id={ + 'type': 'user_edit-form-value', + 'index': 'status' + }, options=[ { 'label': '正常', @@ -792,7 +893,11 @@ def render(button_perms): } ), label='用户状态', - id='user-edit-status-form-item', + id={ + 'type': 'user_edit-form-label', + 'index': 'status', + 'required': False + }, labelCol={ 'offset': 1 }, @@ -843,7 +948,10 @@ def render(button_perms): [ fac.AntdFormItem( fac.AntdInput( - id='user-edit-remark', + id={ + 'type': 'user_edit-form-value', + 'index': 'remark' + }, placeholder='请输入内容', allowClear=True, mode='text-area', @@ -852,7 +960,11 @@ def render(button_perms): } ), label='备注', - id='user-edit-remark-form-item', + id={ + 'type': 'user_edit-form-label', + 'index': 'remark', + 'required': False + }, labelCol={ 'offset': 2 }, diff --git a/demo-pictures/dashzsxq.jpg b/demo-pictures/dashzsxq.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2f7be556491f9c54ea01353dbf805d6a61d14fab Binary files /dev/null and b/demo-pictures/dashzsxq.jpg differ diff --git a/demo-pictures/wxcode.jpg b/demo-pictures/wxcode.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2d9a0b1d589e5c4dab0715704cb3f943d553def0 Binary files /dev/null and b/demo-pictures/wxcode.jpg differ diff --git a/requirements.txt b/requirements.txt index 7674277651db03adb803c70a1678c6b8fe64fbc2..f6cbbfeb5df8893342bd100e51344959d67da6f0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -23,7 +23,7 @@ email-validator==2.0.0.post2 et-xmlfile==1.1.0 fastapi==0.95.1 feffery-antd-charts==0.0.1rc17 -feffery-antd-components==0.2.9 +feffery-antd-components==0.2.10rc17 feffery-markdown-components==0.2.10 feffery-utils-components==0.1.28 Flask==2.2.5 @@ -50,7 +50,6 @@ Pillow==10.0.0 plotly==5.14.1 ply==3.11 psutil==5.9.5 -psycopg2==2.9.6 pyasn1==0.5.0 pycparser==2.21 pydantic==1.10.7