大家好~我是
米洛
!
我正在从0到1打造一个开源的接口测试平台, 也在编写一套与之对应的教程
,希望大家多多支持。
欢迎关注我的公众号米洛的测开日记
,获取最新文章教程!
回顾
上一节咱们编写好了操作日志
相关功能,这一节我们就来聊聊怎么展示它,展示操作日志是一部分,个人主页也是另一部分。
当我们脑海
里没有类似的蓝图时,可以借鉴下其他web的效果。比如掘金(注意这不是硬广):
可以看到他大致分成了3块:
- 用户信息,你是谁,你的简介,联系方式等
- 个人动态
- 个人成就以及粉丝等数据
考虑到成就和粉丝
这个概念我们内部可能不太实用,所以我们以个人资料和个人动态为主题,构建我们的个人首页。
参考一家肯定不够的,我们看看github:
这个热力图
和动态
是我们想要展示的。所以我们采用左侧个人信息+右侧热力图/动态的方式展示个人页。
先来看看最终效果:
编写获取操作记录的接口
- 根据时间获取用户的操作数据(对应热力图)
修改PityOperationDao.py
from sqlalchemy import func, select
from app.crud import Mapper
from app.models import async_session
from app.models.operation_log import PityOperationLog
from app.utils.decorator import dao
from app.utils.logger import Log
@dao(PityOperationLog, Log("PityOperationDao"))
class PityOperationDao(Mapper):
@classmethod
async def count_user_activities(cls, user_id, start_time: str, end_time: str):
"""
根据开始/结束时间 获取用户的活动日历(操作记录的数量)
:param user_id:
:param start_time:
:param end_time:
:return:
"""
async with async_session() as session:
async with session.begin():
format_date = func.date_format(PityOperationLog.operate_time, "%Y-%m-%d")
sql = select(format_date, func.count(PityOperationLog.id)).where(
PityOperationLog.operate_time.between(start_time, end_time),
PityOperationLog.user_id == user_id) \
.group_by(format_date).order_by(format_date)
data = await session.execute(sql)
return data.all()
这里的sqlalchemy语句比较复杂,注意2个点即可:
- func
这里的func是时间转换的func,我们操作记录存放的是具体的日期+时间,但我们查询用户操作一般是按日期来,所以我们需要转换下:
func.date_format干的就是这个事情,为了group_by。
这个sql就是筛选出user_id等于要查询用户,并且时间在指定日期
之内的数据,通过group_by拿到每一天的操作次数,最后根据日期排序后返回。
接着创建app/router/operation/operation_log.py
from fastapi import APIRouter, Depends
from sqlalchemy import desc
from app.crud.operation.PityOperationDao import PityOperationDao
from app.handler.fatcory import PityResponse
from app.models.operation_log import PityOperationLog
from app.routers import Permission
router = APIRouter(prefix="/operation")
# 获取用户操作记录热力图以及参与的项目数量
@router.get("/count")
async def list_user_activities(user_id: int, start_time: str, end_time: str, _=Depends(Permission())):
try:
records = await PityOperationDao.count_user_activities(user_id, start_time, end_time)
ans = list()
for r in records:
# 解包日期和数量
date, count = r
ans.append(dict(date=date, count=count))
return PityResponse.success(ans)
except Exception as e:
return PityResponse.failed(e)
获取到数据后,把日期和date组合成json数组。
- 编写获取用户操作日志详情的接口
# 获取用户操作记录
@router.get("/list")
async def list_user_operation(start_time: str, end_time: str, user_id: int, tag: str = None, _=Depends(Permission())):
try:
records = await PityOperationDao.list_record(user_id=user_id, tag=tag, condition=[
PityOperationLog.operate_time.between(start_time, end_time)], desc=[desc(PityOperationLog.operate_time)])
return PityResponse.records(records)
except Exception as e:
return PityResponse.failed(e)
调用Mapper自带的list_record方法,根据条件筛选出对应的数据并返回
。这把在PityResponse
里封装了一个records方法:
@staticmethod
def records(data: list, code=0, msg="操作成功"):
return dict(code=code, msg=msg, data=PityResponse.model_to_list(data))
这样就不用每次都model_to_list了。
前端页面
- 在route.js加入member路由,不在菜单里展示
- 接着是编写UserInfo.jsx
代码我就不贴了,github都有详细的,有兴趣的可以拉下来看看。
大概也就是根据接口的返回,生成对应的动态
和个人资料页面。
封装个人用户组件
import React from 'react';
import {Avatar} from "antd";
import styles from "@/components/GlobalHeader/index.less";
import {CONFIG} from "@/consts/config";
import {Tooltip} from "antd";
export default ({user, size = 24, marginLeft = 4}) => {
if (user === undefined) {
return '加载中...'
}
// 是否和左边有距离,有的话则为2
return (
<>
<Avatar size={size} className={styles.avatar}
src={user.avatar || `${CONFIG.AVATAR_URL}${user.name}`} alt="avatar"/>
<Tooltip title="点击可查看用户资料">
<a style={{marginLeft: marginLeft}} href={`/#/member/${user.id}`} target="_blank"
rel="noreferrer">{user.name}</a>
</Tooltip>
</>
)
}
这个组件接受用户信息,和头像尺寸
。为啥要这个组件呢?
因为我们的用户资料页面没有提供入口,也就是说菜单里找不到。再者,我们需要把用户名改为头像+用户名,这样看起来更nice。
看看实战效果:
点击链接就可以到个人资料
了。
今天的内容就说到这里了,希望对大家有帮助。