update
This commit is contained in:
parent
2950cf2648
commit
c62ae3af9c
@ -1,5 +1,5 @@
|
|||||||
import pymongo
|
import pymongo
|
||||||
from fastapi import APIRouter, Depends
|
from fastapi import APIRouter, Depends, Request
|
||||||
from motor.motor_asyncio import AsyncIOMotorDatabase
|
from motor.motor_asyncio import AsyncIOMotorDatabase
|
||||||
import crud, schemas
|
import crud, schemas
|
||||||
|
|
||||||
@ -56,33 +56,38 @@ async def move(
|
|||||||
|
|
||||||
@router.post("/add_report")
|
@router.post("/add_report")
|
||||||
async def add_report(data_in: schemas.AddReport,
|
async def add_report(data_in: schemas.AddReport,
|
||||||
game:str,
|
game: str,
|
||||||
db: AsyncIOMotorDatabase = Depends(get_database),
|
db: AsyncIOMotorDatabase = Depends(get_database),
|
||||||
current_user: schemas.UserDB = Depends(deps.get_current_user)
|
current_user: schemas.UserDB = Depends(deps.get_current_user)
|
||||||
):
|
):
|
||||||
"""添加报表"""
|
"""添加报表"""
|
||||||
|
reports = [item.dict() for item in data_in.report_ids]
|
||||||
res = await crud.dashboard.update_one(db, {'_id': data_in.id},
|
res = await crud.dashboard.update_one(db, {'_id': data_in.id},
|
||||||
{'$push': {'reports': {'$each': data_in.report_ids}}})
|
{'$push': {'reports': {'$each': reports}}})
|
||||||
return schemas.Msg(code=0, msg='ok', data='ok')
|
return schemas.Msg(code=0, msg='ok', data='ok')
|
||||||
|
|
||||||
|
|
||||||
@router.post("/del_report")
|
@router.post("/del_report")
|
||||||
async def del_report(data_in: schemas.DelReport,
|
async def del_report(
|
||||||
db: AsyncIOMotorDatabase = Depends(get_database),
|
game: str,
|
||||||
current_user: schemas.UserDB = Depends(deps.get_current_user)
|
data_in: schemas.DelReport,
|
||||||
):
|
db: AsyncIOMotorDatabase = Depends(get_database),
|
||||||
|
current_user: schemas.UserDB = Depends(deps.get_current_user)
|
||||||
|
):
|
||||||
"""删除报表"""
|
"""删除报表"""
|
||||||
for item in data_in.report_ids:
|
del_item = {'report_id': data_in.report_id}
|
||||||
await crud.dashboard.update_one(db, {'_id': data_in.id}, {'$pull': {'reports': item}})
|
await crud.dashboard.update_one(db, {'_id': data_in.id}, {'$pull': {'reports': del_item}})
|
||||||
return schemas.Msg(code=0, msg='ok', data='ok')
|
return schemas.Msg(code=0, msg='ok', data='ok')
|
||||||
|
|
||||||
|
|
||||||
@router.get("/")
|
@router.post("/")
|
||||||
async def dashboards(_id: str,
|
async def dashboards(request: Request,
|
||||||
|
game: str,
|
||||||
|
data_in: schemas.ReadDashboard,
|
||||||
db: AsyncIOMotorDatabase = Depends(get_database),
|
db: AsyncIOMotorDatabase = Depends(get_database),
|
||||||
current_user: schemas.UserDB = Depends(deps.get_current_user)
|
current_user: schemas.UserDB = Depends(deps.get_current_user)
|
||||||
):
|
):
|
||||||
"""获取一个看板"""
|
"""获取一个看板"""
|
||||||
res = await crud.dashboard.get(db, id=_id)
|
res = await crud.dashboard.get(db, id=data_in.id)
|
||||||
res['reports'] = await crud.report.find_many(db, **{'$in': {'_id': res.get('reports')}})
|
# res['reports'] = await crud.report.find_many(db, **{'_id': {'$in': [item['report_id'] for item in res.get('reports')]}})
|
||||||
return schemas.Msg(code=0, msg='ok', data=res['reports'])
|
return schemas.Msg(code=0, msg='ok', data=res['reports'])
|
||||||
|
@ -223,7 +223,7 @@ async def read_kanban(
|
|||||||
for d in dashboards:
|
for d in dashboards:
|
||||||
res['kanban'][-1]['children'].append({
|
res['kanban'][-1]['children'].append({
|
||||||
'name': d['name'],
|
'name': d['name'],
|
||||||
'_id': item['_id']
|
'_id': d['_id']
|
||||||
})
|
})
|
||||||
|
|
||||||
# 我的空间
|
# 我的空间
|
||||||
|
@ -11,6 +11,8 @@ from api import deps
|
|||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@router.post("/create")
|
@router.post("/create")
|
||||||
async def create(
|
async def create(
|
||||||
request: Request,
|
request: Request,
|
||||||
@ -37,9 +39,24 @@ async def read_report(
|
|||||||
current_user: schemas.UserDB = Depends(deps.get_current_user)
|
current_user: schemas.UserDB = Depends(deps.get_current_user)
|
||||||
) -> Any:
|
) -> Any:
|
||||||
"""获取已建报表"""
|
"""获取已建报表"""
|
||||||
|
ext_where = dict()
|
||||||
|
dashboard = dict()
|
||||||
|
if data_in.report_id:
|
||||||
|
ext_where = {'_id': {'$in': data_in.report_id}}
|
||||||
|
if data_in.dashboard_id:
|
||||||
|
dashboard = await crud.dashboard.get(db, id=data_in.dashboard_id)
|
||||||
|
# projection = {'query': False}
|
||||||
|
projection = None
|
||||||
|
reports = await crud.report.read_report(db, user_id=request.user.id, project_id=data_in.project_id,
|
||||||
|
projection=projection, **ext_where)
|
||||||
|
|
||||||
data = await crud.report.read_report(db, user_id=request.user.id, project_id=data_in.project_id)
|
for item in reports:
|
||||||
return schemas.Msg(code=0, msg='ok', data=data)
|
item['added'] = False
|
||||||
|
added_ids = [item['report_id'] for item in dashboard.get('reports', [])]
|
||||||
|
if item['_id'] in added_ids:
|
||||||
|
item['added'] = True
|
||||||
|
|
||||||
|
return schemas.Msg(code=0, msg='ok', data=reports)
|
||||||
|
|
||||||
|
|
||||||
@router.post("/delete")
|
@router.post("/delete")
|
||||||
|
@ -76,7 +76,7 @@ class Settings(BaseSettings):
|
|||||||
'median': lambda x: func.median(x),
|
'median': lambda x: func.median(x),
|
||||||
'max': lambda x: func.max(x),
|
'max': lambda x: func.max(x),
|
||||||
'min': lambda x: func.min(x),
|
'min': lambda x: func.min(x),
|
||||||
'distinct_count': lambda x: func.count(func.distinct(x)),
|
'distinct_count': lambda x: func.uniqCombined(x),
|
||||||
}
|
}
|
||||||
|
|
||||||
CK_OPERATOR = {
|
CK_OPERATOR = {
|
||||||
@ -244,6 +244,12 @@ class Settings(BaseSettings):
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
ARITHMETIC = {
|
||||||
|
'+': lambda x, y: x + y,
|
||||||
|
'-': lambda x, y: x - y,
|
||||||
|
'x': lambda x, y: x * y,
|
||||||
|
'/': lambda x, y: x / y,
|
||||||
|
}
|
||||||
|
|
||||||
PROPHET_TIME_GRAIN_MAP = {
|
PROPHET_TIME_GRAIN_MAP = {
|
||||||
"PT1S": "S",
|
"PT1S": "S",
|
||||||
|
@ -10,8 +10,8 @@ class CRUDBase:
|
|||||||
async def get(self, db, id: Union[ObjectId, str]) -> dict:
|
async def get(self, db, id: Union[ObjectId, str]) -> dict:
|
||||||
return (await db[self.coll_name].find_one({'_id': id})) or dict()
|
return (await db[self.coll_name].find_one({'_id': id})) or dict()
|
||||||
|
|
||||||
async def find_one(self, db, filter=None, *args, **kwargs):
|
async def find_one(self, db, projection=None, *args, **kwargs):
|
||||||
return (await db[self.coll_name].find_one(filter, *args, **kwargs)) or dict()
|
return (await db[self.coll_name].find_one(projection, *args, **kwargs)) or dict()
|
||||||
|
|
||||||
async def read_have(self, db, v: str, **kwargs):
|
async def read_have(self, db, v: str, **kwargs):
|
||||||
where = {'members': v}
|
where = {'members': v}
|
||||||
@ -19,8 +19,8 @@ class CRUDBase:
|
|||||||
cursor = db[self.coll_name].find(where)
|
cursor = db[self.coll_name].find(where)
|
||||||
return await cursor.to_list(length=9999)
|
return await cursor.to_list(length=9999)
|
||||||
|
|
||||||
async def find_many(self, db, **kwargs):
|
async def find_many(self, db, projection=None, **kwargs):
|
||||||
cursor = db[self.coll_name].find(kwargs)
|
cursor = db[self.coll_name].find(kwargs, projection)
|
||||||
return await cursor.to_list(length=9999)
|
return await cursor.to_list(length=9999)
|
||||||
|
|
||||||
def find(self, db, *args, **kwargs):
|
def find(self, db, *args, **kwargs):
|
||||||
|
@ -21,8 +21,8 @@ class CRUDReport(CRUDBase):
|
|||||||
[('project_id', pymongo.DESCENDING), ('name', pymongo.DESCENDING), ('user_id', pymongo.DESCENDING)],
|
[('project_id', pymongo.DESCENDING), ('name', pymongo.DESCENDING), ('user_id', pymongo.DESCENDING)],
|
||||||
unique=True)
|
unique=True)
|
||||||
|
|
||||||
async def read_report(self, db, user_id, project_id):
|
async def read_report(self, db, user_id, project_id, projection=None, **kwargs):
|
||||||
res = await self.find_many(db, user_id=user_id, project_id=project_id)
|
res = await self.find_many(db, user_id=user_id, project_id=project_id,projection=projection, **kwargs)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,8 +9,11 @@ import pandas as pd
|
|||||||
|
|
||||||
from sqlalchemy import func, or_, and_, not_
|
from sqlalchemy import func, or_, and_, not_
|
||||||
|
|
||||||
|
import crud
|
||||||
import schemas
|
import schemas
|
||||||
from core.config import settings
|
from core.config import settings
|
||||||
|
from db import get_database
|
||||||
|
|
||||||
from db.redisdb import get_redis_pool, RedisDrive
|
from db.redisdb import get_redis_pool, RedisDrive
|
||||||
|
|
||||||
|
|
||||||
@ -20,8 +23,9 @@ class BehaviorAnalysis:
|
|||||||
self.rdb = rdb
|
self.rdb = rdb
|
||||||
self.user_tbl = None
|
self.user_tbl = None
|
||||||
self.event_tbl = None
|
self.event_tbl = None
|
||||||
self.event_view = data_in.eventView
|
self.data_in = data_in
|
||||||
self.events = data_in.events
|
self.event_view = dict()
|
||||||
|
self.events = [dict()]
|
||||||
|
|
||||||
self.zone_time: int = 0
|
self.zone_time: int = 0
|
||||||
self.start_date = None
|
self.start_date = None
|
||||||
@ -33,6 +37,15 @@ class BehaviorAnalysis:
|
|||||||
self.unit_num = None
|
self.unit_num = None
|
||||||
|
|
||||||
async def init(self):
|
async def init(self):
|
||||||
|
if self.data_in.report_id:
|
||||||
|
db = get_database()
|
||||||
|
report = await crud.report.get(db, id=self.data_in.report_id)
|
||||||
|
self.event_view = report['query']['eventView']
|
||||||
|
self.events = report['query']['events']
|
||||||
|
else:
|
||||||
|
self.event_view = self.data_in.eventView
|
||||||
|
self.events = self.data_in.events
|
||||||
|
|
||||||
await self._init_table()
|
await self._init_table()
|
||||||
self.zone_time = self._get_zone_time()
|
self.zone_time = self._get_zone_time()
|
||||||
self.time_particle = self._get_time_particle_size()
|
self.time_particle = self._get_time_particle_size()
|
||||||
@ -164,53 +177,92 @@ class BehaviorAnalysis:
|
|||||||
'unit_num': self.unit_num
|
'unit_num': self.unit_num
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def custom_event(self, s):
|
||||||
|
def f(m):
|
||||||
|
if len(m) == 3:
|
||||||
|
event_name, attr, comp = m
|
||||||
|
return getattr(func, comp)(getattr(func, 'if')(getattr(self.event_tbl.c, '#event_name') == event_name,
|
||||||
|
getattr(self.event_tbl.c, attr), 0))
|
||||||
|
elif len(m) == 2:
|
||||||
|
event_name, comp = m
|
||||||
|
# 总次数
|
||||||
|
if comp == 'total_count':
|
||||||
|
return func.sum(getattr(func, 'if')(getattr(self.event_tbl.c, '#event_name') == event_name, 1, 0))
|
||||||
|
elif comp == 'touch_user_count':
|
||||||
|
return func.uniqCombined(getattr(func, 'if')(getattr(self.event_tbl.c, '#event_name') == event_name,
|
||||||
|
getattr(self.event_tbl.c, 'binduid'), 0))
|
||||||
|
elif comp == 'touch_user_avg':
|
||||||
|
return func.divide(
|
||||||
|
func.sum(getattr(func, 'if')(getattr(self.event_tbl.c, '#event_name') == event_name, 1, 0)),
|
||||||
|
func.uniqCombined(getattr(func, 'if')(getattr(self.event_tbl.c, '#event_name') == event_name,
|
||||||
|
getattr(self.event_tbl.c, 'binduid'), 0)))
|
||||||
|
|
||||||
|
opt = ({'+', '-', '*', '/'} & set(s)).pop()
|
||||||
|
a, b = s.split(opt)
|
||||||
|
r1 = a.split('.')
|
||||||
|
r2 = b.split('.')
|
||||||
|
return {'event_name': [r1[0], r2[0]],
|
||||||
|
'select': (settings.ARITHMETIC[opt](f(r1), f(r2))).label('values')
|
||||||
|
}
|
||||||
|
|
||||||
def event_model_sql(self):
|
def event_model_sql(self):
|
||||||
sqls = []
|
sqls = []
|
||||||
event_time_col = getattr(self.event_tbl.c, '#event_time')
|
event_time_col = getattr(self.event_tbl.c, '#event_time')
|
||||||
select_exprs = [
|
|
||||||
settings.TIME_GRAIN_EXPRESSIONS[self.time_particle](event_time_col, self.zone_time)]
|
|
||||||
select_exprs += self.groupby
|
|
||||||
|
|
||||||
for event in self.events:
|
for event in self.events:
|
||||||
event_name = event['event_name']
|
select_exprs = [
|
||||||
event_name_col = getattr(self.event_tbl.c, '#event_name')
|
settings.TIME_GRAIN_EXPRESSIONS[self.time_particle](event_time_col, self.zone_time)]
|
||||||
|
|
||||||
base_where = [
|
base_where = [
|
||||||
func.addHours(event_time_col, self.zone_time) >= self.start_date,
|
func.addHours(event_time_col, self.zone_time) >= self.start_date,
|
||||||
func.addHours(event_time_col, self.zone_time) <= self.end_date,
|
func.addHours(event_time_col, self.zone_time) <= self.end_date,
|
||||||
event_name_col == event_name
|
|
||||||
]
|
]
|
||||||
analysis = event['analysis']
|
event_name_col = getattr(self.event_tbl.c, '#event_name')
|
||||||
event_filter, user_filter = self.handler_filts(*event['filts'])
|
if event.get('customEvent'):
|
||||||
|
formula = event.get('customEvent')
|
||||||
u_account_id_col = getattr(self.user_tbl.c, '#account_id')
|
custom = self.custom_event(formula)
|
||||||
# 按账号聚合
|
event_name = custom['event_name']
|
||||||
e_account_id_col = getattr(self.event_tbl.c, '#account_id')
|
where = [event_name_col.in_(event_name)]
|
||||||
|
event_filter, _ = self.handler_filts(*event['filts'])
|
||||||
# 聚合方式
|
qry = sa.select(
|
||||||
if analysis == 'total_count':
|
*select_exprs,
|
||||||
selectd = select_exprs + [func.count().label('values')]
|
custom['select']
|
||||||
elif analysis == 'touch_user_count':
|
).where(*base_where, *where, *event_filter)
|
||||||
selectd = select_exprs + [func.count(sa.distinct(e_account_id_col)).label('values')]
|
|
||||||
elif analysis == 'touch_user_avg':
|
|
||||||
selectd = select_exprs + [
|
|
||||||
func.round((func.count() / func.count(sa.distinct(e_account_id_col))), 2).label(
|
|
||||||
'values')]
|
|
||||||
|
|
||||||
elif analysis == 'distinct_count':
|
|
||||||
selectd = select_exprs + [
|
|
||||||
func.count(sa.distinct(getattr(self.event_tbl.c, event['event_attr_id']))).label('values')]
|
|
||||||
else:
|
else:
|
||||||
selectd = select_exprs + [
|
event_name = event['event_name']
|
||||||
func.round(getattr(func, analysis)(getattr(self.event_tbl.c, event['event_attr_id'])), 2).label(
|
|
||||||
'values')]
|
|
||||||
|
|
||||||
if user_filter:
|
select_exprs += self.groupby
|
||||||
qry = sa.select(selectd).select_from(
|
|
||||||
self.event_tbl.join(self.user_tbl, u_account_id_col == e_account_id_col)).where(
|
|
||||||
and_(*user_filter, *event_filter, *base_where))
|
|
||||||
|
|
||||||
else:
|
base_where.append(event_name_col == event_name)
|
||||||
qry = sa.select(selectd).where(and_(*event_filter, *base_where))
|
|
||||||
|
analysis = event['analysis']
|
||||||
|
event_filter, user_filter = self.handler_filts(*event['filts'])
|
||||||
|
|
||||||
|
u_account_id_col = getattr(self.user_tbl.c, '#account_id')
|
||||||
|
# 按账号聚合
|
||||||
|
e_account_id_col = getattr(self.event_tbl.c, '#account_id')
|
||||||
|
|
||||||
|
# 聚合方式
|
||||||
|
if analysis == 'total_count':
|
||||||
|
selectd = select_exprs + [func.count().label('values')]
|
||||||
|
elif analysis == 'touch_user_count':
|
||||||
|
selectd = select_exprs + [func.count(sa.distinct(e_account_id_col)).label('values')]
|
||||||
|
elif analysis == 'touch_user_avg':
|
||||||
|
selectd = select_exprs + [
|
||||||
|
func.round((func.count() / func.count(sa.distinct(e_account_id_col))), 2).label(
|
||||||
|
'values')]
|
||||||
|
else:
|
||||||
|
selectd = select_exprs + [
|
||||||
|
func.round(getattr(func, analysis)(getattr(self.event_tbl.c, event['event_attr_id'])), 2).label(
|
||||||
|
'values')]
|
||||||
|
|
||||||
|
if user_filter:
|
||||||
|
qry = sa.select(selectd).select_from(
|
||||||
|
self.event_tbl.join(self.user_tbl, u_account_id_col == e_account_id_col)).where(
|
||||||
|
and_(*user_filter, *event_filter, *base_where))
|
||||||
|
|
||||||
|
else:
|
||||||
|
qry = sa.select(selectd).where(and_(*event_filter, *base_where))
|
||||||
|
|
||||||
qry = qry.group_by(*select_exprs)
|
qry = qry.group_by(*select_exprs)
|
||||||
qry = qry.order_by(sa.Column('date'))
|
qry = qry.order_by(sa.Column('date'))
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import uuid
|
import uuid
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import List
|
from typing import List, Dict
|
||||||
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
@ -20,6 +20,10 @@ class DashboardCreate(DashboardBase):
|
|||||||
pid: str
|
pid: str
|
||||||
|
|
||||||
|
|
||||||
|
class ReadDashboard(BaseModel):
|
||||||
|
id: str
|
||||||
|
|
||||||
|
|
||||||
class DashboardDelete(DBBase):
|
class DashboardDelete(DBBase):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -35,12 +39,18 @@ class DashboardMove(BaseModel):
|
|||||||
cat: Category
|
cat: Category
|
||||||
|
|
||||||
|
|
||||||
|
class Report(BaseModel):
|
||||||
|
report_id: str
|
||||||
|
graph_type: str
|
||||||
|
model: str
|
||||||
|
|
||||||
|
|
||||||
class AddReport(DBBase):
|
class AddReport(DBBase):
|
||||||
report_ids: List[str]
|
report_ids: List[Report]
|
||||||
|
|
||||||
|
|
||||||
class DelReport(DBBase):
|
class DelReport(DBBase):
|
||||||
report_ids: List[str]
|
report_id: str
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------
|
# --------------------------------------------------------------
|
||||||
|
@ -29,6 +29,8 @@ class ReportDelete(DBBase):
|
|||||||
|
|
||||||
class ReportRead(BaseModel):
|
class ReportRead(BaseModel):
|
||||||
project_id: str
|
project_id: str
|
||||||
|
report_id: List = []
|
||||||
|
dashboard_id: str = None
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------
|
# --------------------------------------------------------------
|
||||||
|
@ -9,5 +9,6 @@ class Sql(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class CkQuery(BaseModel):
|
class CkQuery(BaseModel):
|
||||||
eventView: dict
|
eventView: dict = None
|
||||||
events: Union[List[dict],dict]
|
events: Union[List[dict], dict] = None
|
||||||
|
report_id: str = None
|
||||||
|
Loading…
Reference in New Issue
Block a user