You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

425 lines
16 KiB

1 month ago
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
from server import app
from utils.tree_tool import list_to_tree
from views.system.menu.components import content_type, menu_type, button_type
from api.menu import get_menu_tree_api, get_menu_tree_for_edit_option_api, get_menu_list_api, delete_menu_api, get_menu_detail_api
@app.callback(
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,
status=status_select
)
if search_click or refresh_click or operations or fold_click:
table_info = get_menu_list_api(query_params)
default_expanded_row_keys = []
if table_info['code'] == 200:
table_data = table_info['data']['rows']
for item in table_data:
default_expanded_row_keys.append(str(item['menu_id']))
item['key'] = str(item['menu_id'])
item['icon'] = [
{
'type': 'link',
'icon': item['icon'],
'disabled': True,
'style': {
'color': 'rgba(0, 0, 0, 0.8)'
}
},
]
if item['status'] == '1':
item['operation'] = [
{
'content': '修改',
'type': 'link',
'icon': 'antd-edit'
} if 'system:menu:edit' in button_perms else {},
{
'content': '删除',
'type': 'link',
'icon': 'antd-delete'
} if 'system:menu:remove' in button_perms else {},
]
else:
item['operation'] = [
{
'content': '修改',
'type': 'link',
'icon': 'antd-edit'
} if 'system:menu:edit' in button_perms else {},
{
'content': '新增',
'type': 'link',
'icon': 'antd-plus'
} if 'system:menu:add' in button_perms else {},
{
'content': '删除',
'type': 'link',
'icon': 'antd-delete'
} if 'system:menu:remove' in button_perms else {},
]
if item['status'] == '0':
item['status'] = dict(tag='正常', color='blue')
else:
item['status'] = dict(tag='停用', color='volcano')
table_data_new = list_to_tree(table_data, 'menu_id', 'parent_id')
if fold_click:
if not in_default_expanded_row_keys:
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) => {
if (reset_click) {
return [null, null, {'type': 'reset'}]
}
return window.dash_clientside.no_update;
}
''',
[Output('menu-menu_name-input', 'value'),
Output('menu-status-select', 'value'),
Output('menu-operations-store', 'data')],
Input('menu-reset', 'nClicks'),
prevent_initial_call=True
)
# 隐藏/显示菜单搜索表单回调
app.clientside_callback(
'''
(hidden_click, hidden_status) => {
if (hidden_click) {
return [
!hidden_status,
hidden_status ? '隐藏搜索' : '显示搜索'
]
}
return window.dash_clientside.no_update;
}
''',
[Output('menu-search-form-container', 'hidden'),
Output('menu-hidden-tooltip', 'title')],
Input('menu-hidden', 'nClicks'),
State('menu-search-form-container', 'hidden'),
prevent_initial_call=True
)
@app.callback(
[Output('menu-icon', 'value'),
Output('menu-icon', 'prefix')],
Input('icon-category', 'value'),
prevent_initial_call=True
)
def get_select_icon(icon):
"""
获取新增或编辑表单中选择的icon回调
"""
if icon:
return [
icon,
fac.AntdIcon(icon=icon)
]
raise PreventUpdate
@app.callback(
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='')
if clicked_content == '修改':
tree_info = get_menu_tree_for_edit_option_api(menu_params)
else:
tree_info = get_menu_tree_api(menu_params)
if tree_info['code'] == 200:
tree_data = tree_info['data']
if trigger_id == {'index': 'add', 'type': 'menu-operation-button'}:
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 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 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(
[Output('content-by-menu-type', 'children'),
Output('content-by-menu-type', 'key'),
Output('menu-modal-menu-type-store', 'data')],
Input('menu-menu_type', 'value'),
prevent_initial_call=True
)
def get_bottom_content(menu_value):
"""
根据不同菜单类型渲染不同的子区域
"""
if menu_value == 'M':
return [content_type.render(), str(uuid.uuid4()), {'type': 'M'}]
elif menu_value == 'C':
return [menu_type.render(), str(uuid.uuid4()), {'type': 'C'}]
elif menu_value == 'F':
return [button_type.render(), str(uuid.uuid4()), {'type': 'F'}]
raise PreventUpdate
@app.callback(
[Output('menu-modal-M-trigger', 'data'),
Output('menu-modal-C-trigger', 'data'),
Output('menu-modal-F-trigger', 'data')],
Input('menu-modal', 'okCounts'),
State('menu-modal-menu-type-store', 'data'),
)
def modal_confirm_trigger(confirm, menu_type):
"""
增加触发器根据不同菜单类型触发不同的回调解决组件不存在回调异常的问题
"""
if confirm:
if menu_type.get('type') == 'M':
return [
{'timestamp': time.time()},
dash.no_update,
dash.no_update
]
if menu_type.get('type') == 'C':
return [
dash.no_update,
{'timestamp': time.time()},
dash.no_update
]
if menu_type.get('type') == 'F':
return [
dash.no_update,
dash.no_update,
{'timestamp': time.time()}
]
raise PreventUpdate
@app.callback(
[Output('menu-delete-text', 'children'),
Output('menu-delete-confirm-modal', 'visible'),
Output('menu-delete-ids-store', 'data')],
[Input('menu-list-table', 'nClicksButton')],
[State('menu-list-table', 'clickedContent'),
State('menu-list-table', 'recentlyButtonClickedRow')],
prevent_initial_call=True
)
def menu_delete_modal(button_click, clicked_content, recently_button_clicked_row):
"""
显示删除菜单二次确认弹窗回调
"""
if button_click:
if clicked_content == '删除':
menu_ids = recently_button_clicked_row['key']
else:
return dash.no_update
return [
f'是否确认删除菜单编号为{menu_ids}的菜单?',
True,
{'menu_ids': menu_ids}
]
raise PreventUpdate
@app.callback(
[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-delete-confirm-modal', 'okCounts'),
State('menu-delete-ids-store', 'data'),
prevent_initial_call=True
)
def menu_delete_confirm(delete_confirm, menu_ids_data):
"""
删除菜单弹窗确认回调实现删除操作
"""
if delete_confirm:
params = menu_ids_data
delete_button_info = delete_menu_api(params)
if delete_button_info['code'] == 200:
return [
{'type': 'delete'},
{'timestamp': time.time()},
fuc.FefferyFancyMessage('删除成功', type='success')
]
return [
dash.no_update,
{'timestamp': time.time()},
fuc.FefferyFancyMessage('删除失败', type='error')
]
raise PreventUpdate