From 0d6f81c251eb1ca7f63e4d47e6e257998ac015ca Mon Sep 17 00:00:00 2001 From: xlf <3055204202@qq.com> Date: Thu, 14 Sep 2023 09:17:42 +0800 Subject: [PATCH 1/6] =?UTF-8?q?fix:=E4=BF=AE=E5=A4=8D=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E6=B3=A8=E8=A7=A3=E5=BC=82=E5=B8=B8=E7=9A=84bug=20#I816F2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dash-fastapi-backend/utils/common_util.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dash-fastapi-backend/utils/common_util.py b/dash-fastapi-backend/utils/common_util.py index a58f989..1cf60f6 100644 --- a/dash-fastapi-backend/utils/common_util.py +++ b/dash-fastapi-backend/utils/common_util.py @@ -5,6 +5,7 @@ from openpyxl import Workbook from openpyxl.styles import Alignment, PatternFill from openpyxl.utils import get_column_letter from openpyxl.worksheet.datavalidation import DataValidation +from typing import List from config.env import CachePathConfig @@ -59,7 +60,7 @@ def bytes2file_response(bytes_info): yield bytes_info -def export_list2excel(list_data: list): +def export_list2excel(list_data: List): """ 工具方法:将需要导出的list数据转化为对应excel的二进制数据 :param list_data: 数据列表 @@ -73,7 +74,7 @@ def export_list2excel(list_data: list): return binary_data -def get_excel_template(header_list: list, selector_header_list: list, option_list: list[dict]): +def get_excel_template(header_list: List, selector_header_list: List, option_list: List[dict]): """ 工具方法:将需要导出的list数据转化为对应excel的二进制数据 :param header_list: 表头数据列表 -- Gitee From 82922ce30145e7895bc84638a426c7a1b14b75e7 Mon Sep 17 00:00:00 2001 From: xlf <3055204202@qq.com> Date: Fri, 15 Sep 2023 16:49:22 +0800 Subject: [PATCH 2/6] =?UTF-8?q?feat:=E6=96=B0=E5=A2=9E=E9=99=90=E5=88=B6?= =?UTF-8?q?=E5=90=8C=E4=B8=80=E8=B4=A6=E5=8F=B7=E4=B8=8D=E8=83=BD=E5=90=8C?= =?UTF-8?q?=E6=97=B6=E7=99=BB=E5=BD=95=E7=A4=BA=E4=BE=8B=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_admin/controller/login_controller.py | 4 ++-- .../module_admin/service/login_service.py | 9 +++------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/dash-fastapi-backend/module_admin/controller/login_controller.py b/dash-fastapi-backend/module_admin/controller/login_controller.py index 3a88f9d..686b9d6 100644 --- a/dash-fastapi-backend/module_admin/controller/login_controller.py +++ b/dash-fastapi-backend/module_admin/controller/login_controller.py @@ -47,8 +47,8 @@ async def login(request: Request, form_data: CustomOAuth2PasswordRequestForm = D await request.app.state.redis.set(f'access_token:{session_id}', access_token, ex=timedelta(minutes=JwtConfig.REDIS_TOKEN_EXPIRE_MINUTES)) # 此方法可实现同一账号同一时间只能登录一次 - # await request.app.state.redis.set(f'{result.user_id}_access_token', access_token, ex=timedelta(minutes=30)) - # await request.app.state.redis.set(f'{result.user_id}_session_id', session_id, ex=timedelta(minutes=30)) + # await request.app.state.redis.set(f'access_token:{result[0].user_id}', access_token, + # ex=timedelta(minutes=JwtConfig.REDIS_TOKEN_EXPIRE_MINUTES)) logger.info('登录成功') # 判断请求是否来自于api文档,如果是返回指定格式的结果,用于修复api文档认证成功后token显示undefined的bug request_from_swagger = request.headers.get('referer').endswith('docs') if request.headers.get('referer') else False diff --git a/dash-fastapi-backend/module_admin/service/login_service.py b/dash-fastapi-backend/module_admin/service/login_service.py index f6b54a0..91eda4f 100644 --- a/dash-fastapi-backend/module_admin/service/login_service.py +++ b/dash-fastapi-backend/module_admin/service/login_service.py @@ -75,15 +75,12 @@ async def get_current_user(request: Request = Request, token: str = Depends(oaut raise AuthException(data="", message="用户token不合法") redis_token = await request.app.state.redis.get(f'access_token:{session_id}') # 此方法可实现同一账号同一时间只能登录一次 - # redis_token = await request.app.state.redis.get(f'{user.user_basic_info[0].user_id}_access_token') - # redis_session = await request.app.state.redis.get(f'{user.user_basic_info[0].user_id}_session_id') + # redis_token = await request.app.state.redis.get(f'access_token:{user.user_basic_info[0].user_id}') if token == redis_token: await request.app.state.redis.set(f'access_token:{session_id}', redis_token, ex=timedelta(minutes=JwtConfig.REDIS_TOKEN_EXPIRE_MINUTES)) - # await request.app.state.redis.set(f'{user.user_basic_info[0].user_id}_access_token', redis_token, - # ex=timedelta(minutes=30)) - # await request.app.state.redis.set(f'{user.user_basic_info[0].user_id}_session_id', redis_session, - # ex=timedelta(minutes=30)) + # await request.app.state.redis.set(f'access_token:{user.user_basic_info[0].user_id}', redis_token, + # ex=timedelta(minutes=JwtConfig.REDIS_TOKEN_EXPIRE_MINUTES)) return CurrentUserInfoServiceResponse( user=user.user_basic_info[0], -- Gitee From c28e32c4c5c617950265519da5d576e877462fde Mon Sep 17 00:00:00 2001 From: xlf <3055204202@qq.com> Date: Sat, 16 Sep 2023 09:43:36 +0800 Subject: [PATCH 3/6] =?UTF-8?q?fix:=E4=BF=AE=E5=A4=8D=E5=AE=9A=E6=97=B6?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E9=BB=98=E8=AE=A4corn=E8=A1=A8=E8=BE=BE?= =?UTF-8?q?=E5=BC=8F=E6=95=B0=E6=8D=AE=E5=BC=82=E5=B8=B8=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dash-fastapi-backend/sql/dash-fastapi.sql | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dash-fastapi-backend/sql/dash-fastapi.sql b/dash-fastapi-backend/sql/dash-fastapi.sql index 8b2657b..3a541bd 100644 --- a/dash-fastapi-backend/sql/dash-fastapi.sql +++ b/dash-fastapi-backend/sql/dash-fastapi.sql @@ -260,9 +260,9 @@ CREATE TABLE `sys_job` ( -- ---------------------------- -- Records of sys_job -- ---------------------------- -INSERT INTO `sys_job` VALUES (1, '系统默认(无参)', 'default', 'default', 'module_task.scheduler_test.job', 'test', NULL, '0/10 * * * * ?', '2', '0', '1', 'admin', '2023-05-23 16:13:34', 'admin', '2023-05-23 16:13:34', ''); -INSERT INTO `sys_job` VALUES (2, '系统默认(有参)', 'sqlalchemy', 'default', 'module_task.scheduler_test.job', 'new', '{\"test\": 111}', '0/15 * * * * ?', '1', '1', '1', 'admin', '2023-05-23 16:13:34', 'admin', '2023-05-23 16:13:34', ''); -INSERT INTO `sys_job` VALUES (3, '系统默认(多参)', 'redis', 'default', 'module_task.scheduler_test.job', NULL, NULL, '0/20 * * * * ?', '3', '1', '1', 'admin', '2023-05-23 16:13:34', '', NULL, ''); +INSERT INTO `sys_job` VALUES (1, '系统默认(无参)', 'default', 'default', 'module_task.scheduler_test.job', 'test', NULL, '0/10 * * * * *', '2', '0', '1', 'admin', '2023-05-23 16:13:34', 'admin', '2023-05-23 16:13:34', ''); +INSERT INTO `sys_job` VALUES (2, '系统默认(有参)', 'sqlalchemy', 'default', 'module_task.scheduler_test.job', 'new', '{\"test\": 111}', '0/15 * * * * *', '1', '1', '1', 'admin', '2023-05-23 16:13:34', 'admin', '2023-05-23 16:13:34', ''); +INSERT INTO `sys_job` VALUES (3, '系统默认(多参)', 'redis', 'default', 'module_task.scheduler_test.job', NULL, NULL, '0/20 * * * * *', '3', '1', '1', 'admin', '2023-05-23 16:13:34', '', NULL, ''); -- ---------------------------- -- Table structure for sys_job_log -- Gitee From da0e00f3b48be1a51a791d5ca3e8a6be876767fa Mon Sep 17 00:00:00 2001 From: xlf <3055204202@qq.com> Date: Sat, 16 Sep 2023 09:47:17 +0800 Subject: [PATCH 4/6] =?UTF-8?q?style:=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../callbacks/monitor_c/logininfor_c.py | 2 +- dash-fastapi-frontend/views/layout/__init__.py | 14 -------------- .../views/system/user/__init__.py | 2 +- 3 files changed, 2 insertions(+), 16 deletions(-) diff --git a/dash-fastapi-frontend/callbacks/monitor_c/logininfor_c.py b/dash-fastapi-frontend/callbacks/monitor_c/logininfor_c.py index 2ec0ffd..754ed98 100644 --- a/dash-fastapi-frontend/callbacks/monitor_c/logininfor_c.py +++ b/dash-fastapi-frontend/callbacks/monitor_c/logininfor_c.py @@ -171,7 +171,7 @@ def login_log_delete_modal(operation_click, selected_row_keys): info_ids = ','.join(selected_row_keys) return [ - f'是否确认删除访问编号为{info_ids}的操作日志?', + f'是否确认删除访问编号为{info_ids}的登录日志?', True, {'oper_type': 'delete', 'info_ids': info_ids} ] diff --git a/dash-fastapi-frontend/views/layout/__init__.py b/dash-fastapi-frontend/views/layout/__init__.py index 88f9f2d..52b992b 100644 --- a/dash-fastapi-frontend/views/layout/__init__.py +++ b/dash-fastapi-frontend/views/layout/__init__.py @@ -19,20 +19,6 @@ def render_content(menu_info): html.Div(id='idle-placeholder-container'), - # 注入相关modal - # html.Div( - # [ - # # 个人资料面板 - # fac.AntdModal( - # render_user_profile(), - # id='index-personal-info-modal', - # title='个人资料', - # width=1000, - # mask=False - # ) - # ] - # ), - # 布局设置抽屉 fac.AntdDrawer( [ diff --git a/dash-fastapi-frontend/views/system/user/__init__.py b/dash-fastapi-frontend/views/system/user/__init__.py index fc81c65..498ba16 100644 --- a/dash-fastapi-frontend/views/system/user/__init__.py +++ b/dash-fastapi-frontend/views/system/user/__init__.py @@ -633,7 +633,7 @@ def render(button_perms): 'width': 200 } ), - label='岗位', + label='角色', id='user-add-role-form-item', labelCol={ 'offset': 8 -- Gitee From 8d66e71508e56975ea264257db08957414ab8fcf Mon Sep 17 00:00:00 2001 From: xlf <3055204202@qq.com> Date: Sat, 16 Sep 2023 09:51:21 +0800 Subject: [PATCH 5/6] =?UTF-8?q?docs:=E6=9B=B4=E6=96=B0README=E6=96=87?= =?UTF-8?q?=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9c8b8db..04caeaf 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,14 @@

logo

-

Dash-FastAPI-Admin v1.0.2

+

Dash-FastAPI-Admin v1.0.4

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

- + + +

## 平台简介 @@ -85,7 +87,7 @@ Dash-FastAPI-Admin是一套全部开源的快速开发平台,毫无保留给 git clone https://gitee.com/insistence2022/dash-fastapi-admin.git # 进入项目根目录 -cd Dash-FastAPI-Admin +cd dash-fastapi-admin # 安装项目依赖环境 pip3 install -r requirements.txt -- Gitee From cdb1ea8669d5f4bdcc24fb00d8e018ef56bcf74c Mon Sep 17 00:00:00 2001 From: xlf <3055204202@qq.com> Date: Sat, 16 Sep 2023 09:52:12 +0800 Subject: [PATCH 6/6] =?UTF-8?q?feat:=E6=96=B0=E5=A2=9E=E9=A6=96=E9=A1=B5?= =?UTF-8?q?=E6=A8=A1=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dash-fastapi-frontend/views/__init__.py | 1 + .../views/dashboard/__init__.py | 8 + .../views/dashboard/components/page_bottom.py | 533 ++++++++++++++++++ .../views/dashboard/components/page_top.py | 148 +++++ .../views/layout/components/content.py | 8 +- 5 files changed, 693 insertions(+), 5 deletions(-) create mode 100644 dash-fastapi-frontend/views/dashboard/__init__.py create mode 100644 dash-fastapi-frontend/views/dashboard/components/page_bottom.py create mode 100644 dash-fastapi-frontend/views/dashboard/components/page_top.py diff --git a/dash-fastapi-frontend/views/__init__.py b/dash-fastapi-frontend/views/__init__.py index 5443387..bc38240 100644 --- a/dash-fastapi-frontend/views/__init__.py +++ b/dash-fastapi-frontend/views/__init__.py @@ -1,5 +1,6 @@ from . import ( layout, + dashboard, system, monitor, tool, diff --git a/dash-fastapi-frontend/views/dashboard/__init__.py b/dash-fastapi-frontend/views/dashboard/__init__.py new file mode 100644 index 0000000..da12fc7 --- /dev/null +++ b/dash-fastapi-frontend/views/dashboard/__init__.py @@ -0,0 +1,8 @@ +from .components import page_top, page_bottom + + +def render_dashboard(): + return [ + page_top.render_page_top(), + page_bottom.render_page_bottom() + ] diff --git a/dash-fastapi-frontend/views/dashboard/components/page_bottom.py b/dash-fastapi-frontend/views/dashboard/components/page_bottom.py new file mode 100644 index 0000000..c5a94c4 --- /dev/null +++ b/dash-fastapi-frontend/views/dashboard/components/page_bottom.py @@ -0,0 +1,533 @@ +from dash import html +import feffery_antd_components as fac +import feffery_utils_components as fuc +import feffery_antd_charts as fact + + +def render_page_bottom(): + # 模拟数据 + radar_origin_data = [ + { + 'name': '个人', + 'ref': 10, + 'koubei': 8, + 'output': 4, + 'contribute': 5, + 'hot': 7 + }, + { + 'name': '团队', + 'ref': 3, + 'koubei': 9, + 'output': 6, + 'contribute': 3, + 'hot': 1 + }, + { + 'name': '部门', + 'ref': 4, + 'koubei': 1, + 'output': 6, + 'contribute': 5, + 'hot': 7 + } + ] + + radar_data = [] + radar_title_map = { + 'ref': '引用', + 'koubei': '口碑', + 'output': '产量', + 'contribute': '贡献', + 'hot': '热度' + } + + for item in radar_origin_data: + for key, value in item.items(): + if key != 'name': + radar_data.append({ + 'name': item['name'], + 'label': radar_title_map[key], + 'value': value + }) + + project_list = [ + { + "id": "xxx1", + "title": "Alipay", + "logo": "https://gw.alipayobjects.com/zos/rmsportal/WdGqmHpayyMjiEhcKoVE.png", + "description": "那是一种内在的东西,他们到达不了,也无法触及的", + "updatedAt": "2023-09-15T01:08:36.135Z", + "member": "科学搬砖组", + "href": "", + "memberLink": "" + }, + { + "id": "xxx2", + "title": "Angular", + "logo": "https://gw.alipayobjects.com/zos/rmsportal/zOsKZmFRdUtvpqCImOVY.png", + "description": "希望是一个好东西,也许是最好的,好东西是不会消亡的", + "updatedAt": "2017-07-24T00:00:00.000Z", + "member": "全组都是吴彦祖", + "href": "", + "memberLink": "" + }, + { + "id": "xxx3", + "title": "Ant Design", + "logo": "https://gw.alipayobjects.com/zos/rmsportal/dURIMkkrRFpPgTuzkwnB.png", + "description": "城镇中有那么多的酒馆,她却偏偏走进了我的酒馆", + "updatedAt": "2023-09-15T01:08:36.135Z", + "member": "中二少女团", + "href": "", + "memberLink": "" + }, + { + "id": "xxx4", + "title": "Ant Design Pro", + "logo": "https://gw.alipayobjects.com/zos/rmsportal/sfjbOqnsXXJgNCjCzDBL.png", + "description": "那时候我只会想自己想要什么,从不想自己拥有什么", + "updatedAt": "2017-07-23T00:00:00.000Z", + "member": "程序员日常", + "href": "", + "memberLink": "" + }, + { + "id": "xxx5", + "title": "Bootstrap", + "logo": "https://gw.alipayobjects.com/zos/rmsportal/siCrBXXhmvTQGWPNLBow.png", + "description": "凛冬将至", + "updatedAt": "2017-07-23T00:00:00.000Z", + "member": "高逼格设计天团", + "href": "", + "memberLink": "" + }, + { + "id": "xxx6", + "title": "React", + "logo": "https://gw.alipayobjects.com/zos/rmsportal/kZzEzemZyKLKFsojXItE.png", + "description": "生命就像一盒巧克力,结果往往出人意料", + "updatedAt": "2017-07-23T00:00:00.000Z", + "member": "骗你来学计算机", + "href": "", + "memberLink": "" + } + ] + + activity_list = [ + { + "id": "trend-1", + "updatedAt": "2023-09-15 01:08:36", + "user": { + "name": "曲丽丽", + "avatar": "https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png" + }, + "group": { + "name": "高逼格设计天团", + "link": "http://github.com/" + }, + "project": { + "name": "六月迭代", + "link": "http://github.com/" + }, + "template": "新建项目" + }, + { + "id": "trend-2", + "updatedAt": "2023-09-15 01:08:36", + "user": { + "name": "付小小", + "avatar": "https://gw.alipayobjects.com/zos/rmsportal/cnrhVkzwxjPwAaCfPbdc.png" + }, + "group": { + "name": "高逼格设计天团", + "link": "http://github.com/" + }, + "project": { + "name": "六月迭代", + "link": "http://github.com/" + }, + "template": "新建项目" + }, + { + "id": "trend-3", + "updatedAt": "2023-09-15 01:08:36", + "user": { + "name": "林东东", + "avatar": "https://gw.alipayobjects.com/zos/rmsportal/gaOngJwsRYRaVAuXXcmB.png" + }, + "group": { + "name": "中二少女团", + "link": "http://github.com/" + }, + "project": { + "name": "六月迭代", + "link": "http://github.com/" + }, + "template": "新建项目" + }, + { + "id": "trend-4", + "updatedAt": "2023-09-15 01:08:36", + "user": { + "name": "周星星", + "avatar": "https://gw.alipayobjects.com/zos/rmsportal/WhxKECPNujWoWEFNdnJE.png" + }, + "group": { + "name": "白鹭酱油开发组", + "link": "http://github.com/" + }, + "project": { + "name": "5 月日常迭代", + "link": "http://github.com/" + }, + "template": "发布了" + }, + { + "id": "trend-5", + "updatedAt": "2023-09-15 01:08:36", + "user": { + "name": "乐哥", + "avatar": "https://gw.alipayobjects.com/zos/rmsportal/jZUIxmJycoymBprLOUbT.png" + }, + "group": { + "name": "程序员日常", + "link": "http://github.com/" + }, + "project": { + "name": "品牌迭代", + "link": "http://github.com/" + }, + "template": "新建项目" + } + ] + + return html.Div( + [ + fac.AntdRow( + [ + fac.AntdCol( + [ + fac.AntdCard( + [ + fac.AntdCardGrid( + [ + html.Div( + [ + fac.AntdAvatar( + mode='image', + src=item.get('logo'), + size='small' + ), + html.A( + item.get('title') + ) + ], + className='card-title' + ), + html.Div( + item.get('description'), + className='card-description' + ), + html.Div( + [ + html.A(item.get('member')), + html.Span( + '9小时前', + className='datetime' + ) + ], + className='project-item' + ) + ] + ) + for item in project_list + ], + className='project-list', + title='进行中的项目', + bordered=False, + extraLink={ + 'content': '全部项目' + }, + bodyStyle={ + 'padding': 0 + }, + style={ + 'marginBottom': '24px', + 'boxShadow': 'rgba(0, 0, 0, 0.1) 0px 4px 12px' + } + ), + fac.AntdCard( + fac.AntdSpace( + [ + html.Div( + [ + html.Div( + [ + html.Div( + fac.AntdAvatar( + mode='image', + src=item.get('user').get('avatar'), + size='small', + ), + style={ + 'flex': '0 1', + 'marginRight': '16px' + } + ), + html.Div( + [ + html.Div( + [ + html.Span(f"{item.get('user').get('name')} 在 "), + html.A(item.get('group').get('name'), href=item.get('group').get('link')), + html.Span(f" {item.get('template')} "), + html.A(item.get('project').get('name'), href=item.get('project').get('link')) + ], + key=item.get('id') + ), + html.Div( + item.get('updatedAt'), + style={ + 'color': 'rgba(0,0,0,.45)', + 'fontSize': '14px', + 'lineHeight': '22px' + } + ), + ], + style={ + 'flex': '1 1 auto' + } + ), + ], + style={ + 'display': 'flex' + } + ), + fac.AntdDivider() + ] + ) + for item in activity_list + ], + direction='vertical', + style={ + 'width': '100%', + 'maxHeight': '500px', + 'overflowY': 'auto' + } + ), + title='动态', + bordered=False, + style={ + 'marginBottom': '24px', + 'boxShadow': 'rgba(0, 0, 0, 0.1) 0px 4px 12px' + } + ), + ], + xl=16, + lg=24, + md=24, + sm=24, + xs=24 + ), + fac.AntdCol( + [ + fac.AntdCard( + html.Div( + [ + html.A('操作一'), + html.A('操作二'), + html.A('操作三'), + html.A('操作四'), + html.A('操作五'), + fac.AntdButton( + '添加', + type="primary", + size='small', + icon=fac.AntdIcon(icon='antd-plus'), + style={ + 'marginLeft': '20px' + } + ) + ], + className='item-group' + ), + title='快速开始 / 便捷导航', + bordered=False, + style={ + 'marginBottom': '24px', + 'boxShadow': 'rgba(0, 0, 0, 0.1) 0px 4px 12px' + } + ), + fac.AntdCard( + html.Div( + fact.AntdRadar( + height=343, + data=radar_data, + xField='label', + yField='value', + seriesField='name', + point={}, + legend={ + 'position': 'bottom' + }, + ), + style={ + 'minHeight': '400px', + 'margin': '0 auto', + 'paddingTop': '30px' + } + ), + title='XX 指数', + bordered=False, + bodyStyle={ + 'padding': 0 + }, + style={ + 'marginBottom': '24px', + 'boxShadow': 'rgba(0, 0, 0, 0.1) 0px 4px 12px' + } + ), + fac.AntdCard( + html.Div( + fac.AntdRow( + [ + fac.AntdCol( + html.A( + [ + fac.AntdAvatar( + mode='image', + src=item.get('logo'), + size='small' + ), + html.Span( + item.get('member'), + className='member' + ) + ] + ), + span=12 + ) + for item in project_list + ] + ), + className='members' + ), + title='团队', + bordered=False, + style={ + 'marginBottom': '24px', + 'boxShadow': 'rgba(0, 0, 0, 0.1) 0px 4px 12px' + } + ), + ], + xl=8, + lg=24, + md=24, + sm=24, + xs=24, + style={ + 'padding': '0 12px' + } + ), + ], + gutter=24 + ), + fuc.FefferyStyle( + rawStyle=''' + .project-list .card-title { + font-size: 0; + } + + .project-list .card-title a { + color: rgba(0, 0, 0, 0.85); + margin-left: 12px; + line-height: 24px; + height: 24px; + display: inline-block; + vertical-align: top; + font-size: 14px; + } + + .project-list .card-title a:hover { + color: #1890ff; + } + + .project-list .card-description { + color: rgba(0, 0, 0, 0.45); + height: 44px; + line-height: 22px; + overflow: hidden; + } + + .project-list .project-item { + display: flex; + margin-top: 8px; + overflow: hidden; + font-size: 12px; + height: 20px; + line-height: 20px; + } + + .project-list .project-item a { + color: rgba(0, 0, 0, 0.45); + display: inline-block; + flex: 1 1 0; + } + + .project-list .project-item a:hover { + color: #1890ff; + } + + .project-list .project-item .datetime { + color: rgba(0, 0, 0, 0.25); + flex: 0 0 auto; + float: right; + } + + .project-list .ant-card-meta-description { + color: rgba(0, 0, 0, 0.45); + height: 44px; + line-height: 22px; + overflow: hidden; + } + + .item-group { + padding: 20px 0 8px 24px; + font-size: 0; + } + + .item-group a { + color: rgba(0, 0, 0, 0.65); + display: inline-block; + font-size: 14px; + margin-bottom: 13px; + width: 25%; + padding-left: 20px; + } + + .members a { + display: block; + margin: 12px 0; + line-height: 24px; + height: 24px; + } + + .members a .member { + font-size: 14px; + color: rgba(0, 0, 0, 0.65); + line-height: 24px; + max-width: 100px; + vertical-align: top; + margin-left: 12px; + transition: all 0.3s; + display: inline-block; + } + + .members a .member:hover span { + color: #1890ff; + } + ''' + ) + ] + ) diff --git a/dash-fastapi-frontend/views/dashboard/components/page_top.py b/dash-fastapi-frontend/views/dashboard/components/page_top.py new file mode 100644 index 0000000..dff95c9 --- /dev/null +++ b/dash-fastapi-frontend/views/dashboard/components/page_top.py @@ -0,0 +1,148 @@ +from dash import html +import feffery_antd_components as fac +import feffery_utils_components as fuc + +from flask import session + + +def render_page_top(): + + return html.Div( + [ + html.Div( + fac.AntdAvatar( + id='dashboard-avatar-info', + mode='image', + src=session.get('user_info').get('avatar'), + size='large' + ), + className='avatar', + ), + html.Div( + [ + html.Div( + fac.AntdText(f"早安,{session.get('user_info').get('nick_name')},祝你开心每一天!"), + className='content-title', + ), + html.Div('交互专家 |蚂蚁金服-某某某事业群-某某平台部-某某技术部-UED') + ], + className='content', + ), + html.Div( + [ + html.Div( + fac.AntdStatistic( + title='项目数', + value=56 + ), + className='stat-item' + ), + html.Div( + fac.AntdStatistic( + title='团队内排名', + value=8, + suffix='/ 24' + ), + className='stat-item' + ), + html.Div( + fac.AntdStatistic( + title='项目访问', + value=2223 + ), + className='stat-item' + ), + ], + className='extra-content' + ), + fuc.FefferyStyle( + rawStyle=''' + .page-header-content { + display: flex; + } + + .page-header-content .avatar { + flex: 0 1 72px; + } + + .page-header-content .avatar > span { + display: block; + width: 72px; + height: 72px; + border-radius: 72px; + } + + .page-header-content .content { + position: relative; + top: 4px; + margin-left: 24px; + line-height: 22px; + color: rgba(0,0,0,.45); + flex: 1 1 auto; + } + + .page-header-content .content .content-title { + margin-bottom: 12px; + font-size: 20px; + font-weight: 500; + line-height: 28px; + color: rgba(0,0,0,.85); + } + + .extra-content { + float: right; + white-space: nowrap; + } + + .extra-content .stat-item { + position: relative; + display: inline-block; + padding: 0 32px; + } + + .extra-content .stat-item > p:first-child { + margin-bottom: 4px; + font-size: 14px; + line-height: 22px; + color: rgba(0,0,0,.45); + } + + .extra-content .stat-item > p { + margin: 0; + font-size: 30px; + line-height: 38px; + color: rgba(0,0,0,.85); + } + + .extra-content .stat-item > p > span { + font-size: 20px; + color: rgba(0,0,0,.45); + } + + .extra-content .stat-item::after { + position: absolute; + top: 8px; + right: 0; + width: 1px; + height: 40px; + background-color: #e8e8e8; + content: ''; + } + + .extra-content .stat-item:last-child { + padding-right: 0; + } + + .extra-content .stat-item:last-child::after { + display: none; + } + ''' + ) + ], + className='page-header-content', + style={ + 'padding': '12px', + 'marginBottom': '24px', + 'boxShadow': 'rgba(0, 0, 0, 0.1) 0px 4px 12px' + } + ) diff --git a/dash-fastapi-frontend/views/layout/components/content.py b/dash-fastapi-frontend/views/layout/components/content.py index 7d17211..454dbd8 100644 --- a/dash-fastapi-frontend/views/layout/components/content.py +++ b/dash-fastapi-frontend/views/layout/components/content.py @@ -1,6 +1,8 @@ from dash import html import feffery_antd_components as fac +from views.dashboard import render_dashboard + def render_main_content(): return [ @@ -14,11 +16,7 @@ def render_main_content(): 'label': '首页', 'key': '首页', 'closable': False, - 'children': fac.AntdAlert( - type='info', - showIcon=True, - message='这里是主标签页,通常建议设置为不可关闭并展示一些总览类型的信息' - ) + 'children': render_dashboard() } ], id='tabs-container', -- Gitee