@@ -0,0 +1,189 @@
|
||||
from django.contrib.admin import AdminSite
|
||||
from django.utils import timezone
|
||||
|
||||
|
||||
class HulumathAdminSite(AdminSite):
|
||||
site_header = "葫芦数学运营后台"
|
||||
site_title = "葫芦数学后台"
|
||||
index_title = "运营总览"
|
||||
site_url = "/"
|
||||
index_template = "admin/index.html"
|
||||
login_template = "admin/login.html"
|
||||
|
||||
APP_ORDER = {
|
||||
"accounts": 10,
|
||||
"math_life": 20,
|
||||
"contest": 30,
|
||||
"content": 40,
|
||||
"latex_lab": 50,
|
||||
"progression": 60,
|
||||
"engagement": 70,
|
||||
"auth": 90,
|
||||
}
|
||||
MODEL_LABELS = {
|
||||
"accounts.user": "用户账号",
|
||||
"accounts.invitecode": "邀请码",
|
||||
"accounts.invitecodeusage": "邀请码使用记录",
|
||||
"accounts.usersession": "登录设备",
|
||||
"accounts.visitormigration": "游客数据迁移",
|
||||
"accounts.auditlog": "管理员审计日志",
|
||||
"math_life.mathidentity": "数学人格",
|
||||
"math_life.mathbtiassessment": "MathBTI 测评版本",
|
||||
"math_life.mathbtiresult": "MathBTI 用户结果",
|
||||
"math_life.character": "剧情人物",
|
||||
"math_life.story": "数学人生",
|
||||
"math_life.storyversion": "人生版本",
|
||||
"math_life.storyrun": "用户人生存档",
|
||||
"math_life.storychoice": "用户选择记录",
|
||||
"math_life.userrelationship": "人物关系",
|
||||
"math_life.skillpackage": "人物 Skill 包",
|
||||
"contest.question": "题目",
|
||||
"contest.questionversion": "题目版本",
|
||||
"contest.contest": "比赛",
|
||||
"contest.contestattempt": "答题记录",
|
||||
"contest.contestanswer": "逐题答案",
|
||||
"contest.realtimematch": "实时对局",
|
||||
"contest.ratinghistory": "Rating 变化",
|
||||
"contest.leaderboardsnapshot": "排行榜快照",
|
||||
"contest.cheatflag": "异常成绩",
|
||||
"content.contentitem": "视频与内容",
|
||||
"content.contentinteraction": "内容互动",
|
||||
"content.videoprogress": "视频观看进度",
|
||||
"latex_lab.formuladocument": "用户公式文档",
|
||||
"latex_lab.formularevision": "公式版本",
|
||||
"latex_lab.latexcourse": "LaTeX 课程",
|
||||
"latex_lab.latexexercise": "LaTeX 练习",
|
||||
"latex_lab.latexattempt": "练习记录",
|
||||
"latex_lab.handwritingrecognitionjob": "手写识别任务",
|
||||
"progression.userpet": "数学精灵",
|
||||
"progression.userability": "五维能力",
|
||||
"progression.card": "数学人物卡",
|
||||
"progression.usercard": "用户卡册",
|
||||
"progression.rewardtransaction": "奖励流水",
|
||||
"auth.group": "后台角色组",
|
||||
}
|
||||
MODEL_ORDER = {
|
||||
label: index
|
||||
for index, label in enumerate(
|
||||
(
|
||||
"用户账号",
|
||||
"邀请码",
|
||||
"邀请码使用记录",
|
||||
"登录设备",
|
||||
"游客数据迁移",
|
||||
"管理员审计日志",
|
||||
"数学人生",
|
||||
"人生版本",
|
||||
"剧情人物",
|
||||
"人物 Skill 包",
|
||||
"数学人格",
|
||||
"MathBTI 测评版本",
|
||||
"用户人生存档",
|
||||
"人物关系",
|
||||
"比赛",
|
||||
"题目",
|
||||
"题目版本",
|
||||
"实时对局",
|
||||
"答题记录",
|
||||
"异常成绩",
|
||||
"视频与内容",
|
||||
"视频观看进度",
|
||||
"内容互动",
|
||||
"LaTeX 课程",
|
||||
"LaTeX 练习",
|
||||
"用户公式文档",
|
||||
"数学精灵",
|
||||
"五维能力",
|
||||
"数学人物卡",
|
||||
"用户卡册",
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
def get_app_list(self, request, app_label=None):
|
||||
app_list = super().get_app_list(request, app_label)
|
||||
for app in app_list:
|
||||
app["models"] = list(app["models"])
|
||||
for model in app["models"]:
|
||||
object_name = model["object_name"].lower()
|
||||
key = f"{app['app_label']}.{object_name}"
|
||||
model["name"] = self.MODEL_LABELS.get(key, model["name"])
|
||||
app["models"].sort(
|
||||
key=lambda model: (
|
||||
self.MODEL_ORDER.get(model["name"], 999),
|
||||
model["name"],
|
||||
)
|
||||
)
|
||||
app_list.sort(
|
||||
key=lambda app: (
|
||||
self.APP_ORDER.get(app["app_label"], 999),
|
||||
app["name"],
|
||||
)
|
||||
)
|
||||
return app_list
|
||||
|
||||
def each_context(self, request):
|
||||
context = super().each_context(request)
|
||||
context["admin_environment"] = "生产运营"
|
||||
return context
|
||||
|
||||
def index(self, request, extra_context=None):
|
||||
from accounts.models import InviteCode, User
|
||||
from content.models import ContentItem
|
||||
from contest.models import CheatFlag, ContestAttempt, RealtimeMatch
|
||||
from math_life.models import StoryRun
|
||||
|
||||
today = timezone.localdate()
|
||||
extra_context = {
|
||||
**(extra_context or {}),
|
||||
"dashboard_metrics": [
|
||||
{
|
||||
"label": "总用户",
|
||||
"value": User.objects.filter(is_active=True).count(),
|
||||
"hint": f"今日新增 {User.objects.filter(date_joined__date=today).count()}",
|
||||
"tone": "green",
|
||||
},
|
||||
{
|
||||
"label": "进行中的人生",
|
||||
"value": StoryRun.objects.filter(status=StoryRun.Status.ACTIVE).count(),
|
||||
"hint": "用户当前存档",
|
||||
"tone": "blue",
|
||||
},
|
||||
{
|
||||
"label": "今日比赛完成",
|
||||
"value": ContestAttempt.objects.filter(
|
||||
submitted_at__date=today
|
||||
).count(),
|
||||
"hint": "含实时与异步",
|
||||
"tone": "orange",
|
||||
},
|
||||
{
|
||||
"label": "已发布内容",
|
||||
"value": ContentItem.objects.filter(is_published=True).count(),
|
||||
"hint": "视频、知识与人物",
|
||||
"tone": "purple",
|
||||
},
|
||||
],
|
||||
"dashboard_alerts": [
|
||||
{
|
||||
"label": "待处理异常成绩",
|
||||
"value": CheatFlag.objects.filter(
|
||||
status=CheatFlag.Status.OPEN
|
||||
).count(),
|
||||
"url": "/admin/contest/cheatflag/?status__exact=open",
|
||||
},
|
||||
{
|
||||
"label": "等待中的实时对局",
|
||||
"value": RealtimeMatch.objects.filter(
|
||||
status=RealtimeMatch.Status.WAITING
|
||||
).count(),
|
||||
"url": "/admin/contest/realtimematch/?status__exact=waiting",
|
||||
},
|
||||
{
|
||||
"label": "可用邀请码",
|
||||
"value": InviteCode.objects.filter(is_active=True).count(),
|
||||
"url": "/admin/accounts/invitecode/",
|
||||
},
|
||||
],
|
||||
}
|
||||
return super().index(request, extra_context)
|
||||
Reference in New Issue
Block a user