201 lines
7.0 KiB
Python
201 lines
7.0 KiB
Python
from fastapi import Depends, HTTPException, Request, Query
|
|
from typing import Literal, Tuple, Union
|
|
|
|
from tortoise.exceptions import DoesNotExist
|
|
|
|
from app.models.base import User
|
|
from app.models.fr import DefinitionFr
|
|
from app.utils.security import get_current_user
|
|
from app.api.admin.router import admin_router
|
|
import app.models.fr as fr
|
|
import app.models.jp as jp
|
|
from app.schemas.admin_schemas import CreateWord, UpdateWordSet, UpdateWord, SearchWordRequest
|
|
|
|
|
|
@admin_router.get("/dict")
|
|
async def get_wordlist(request: Request,
|
|
page: int = Query(1, ge=1),
|
|
page_size: int = Query(10, le=10),
|
|
lang_code: Literal["fr", "jp"] = "fr",
|
|
admin_user: Tuple[User, dict] = Depends(get_current_user)):
|
|
"""
|
|
后台管理系统中关于词典部分的初始界面,分页显示
|
|
:param request: 请求头
|
|
:param page: 显示的表格视窗的页数,起始默认为 1
|
|
:param page_size: 控制每页的单词内容条数
|
|
:param lang_code: 查询并显示对应语言的单词表
|
|
:return: None
|
|
"""
|
|
if not admin_user[0].is_admin:
|
|
raise HTTPException(status_code=403, detail="非管理员,无权限访问")
|
|
offset = (page - 1) * page_size
|
|
if lang_code == "fr":
|
|
total = await fr.DefinitionFr.all().count()
|
|
wordlist = await fr.DefinitionFr.all().offset(offset).limit(page_size).values(
|
|
"word__text",
|
|
"pos",
|
|
"meaning",
|
|
"example",
|
|
"eng_explanation"
|
|
)
|
|
else:
|
|
total = await jp.DefinitionJp.all().count()
|
|
wordlist = await jp.DefinitionJp.all().offset(offset).limit(page_size).values(
|
|
"word__text",
|
|
"pos",
|
|
"meaning",
|
|
"example",
|
|
)
|
|
return {
|
|
"total": total,
|
|
"data": wordlist
|
|
}
|
|
|
|
|
|
@admin_router.post("/dict/search_word")
|
|
async def search_word(
|
|
request: Request,
|
|
search_word: SearchWordRequest,
|
|
admin_user: Tuple[User, dict] = Depends(get_current_user),
|
|
):
|
|
"""
|
|
查询单词
|
|
:param request: 请求体参数
|
|
:param search_word: Pydantic 模型校验:可提供词性筛选
|
|
:param admin_user:
|
|
:return:
|
|
"""
|
|
if not admin_user[0].is_admin:
|
|
raise HTTPException(status_code=403, detail="非管理员,无权限访问")
|
|
# 筛选参数构造
|
|
filter_kwargs = {}
|
|
if search_word.pos:
|
|
filter_kwargs["pos"] = search_word.pos
|
|
if search_word.language == "fr":
|
|
try:
|
|
word_obj = await fr.WordlistFr.get(text=search_word.word)
|
|
except DoesNotExist:
|
|
raise HTTPException(status_code=400, detail=f"词条 {search_word.word} 不存在于法语词表中")
|
|
definitions = await word_obj.definitions.filter(**filter_kwargs)
|
|
result = [{
|
|
"id": d.id,
|
|
"word": word_obj.text,
|
|
"pos": d.pos,
|
|
"meaning": d.meaning,
|
|
"example": d.example,
|
|
"eng_explanation": d.eng_explanation
|
|
} for d in definitions]
|
|
return result
|
|
else:
|
|
try:
|
|
word_obj = await jp.WordlistJp.get(text=search_word.word)
|
|
except DoesNotExist:
|
|
raise HTTPException(status_code=400, detail=f"词条 {search_word.word} 不存在于日语词表中")
|
|
definitions = await word_obj.definitions.filter(**filter_kwargs)
|
|
result = [{
|
|
"id": d.id,
|
|
"word": word_obj.text,
|
|
"pos": d.pos,
|
|
"meaning": d.meaning,
|
|
"example": d.example
|
|
} for d in definitions]
|
|
return result
|
|
|
|
|
|
@admin_router.post("/dict/adjust")
|
|
async def adjust_dict(
|
|
request: Request,
|
|
updated_contents: UpdateWordSet,
|
|
admin_user: Tuple[User, dict] = Depends(get_current_user)
|
|
):
|
|
"""
|
|
只关心更新的内容,不关心未改变的内容。
|
|
批量更新 Definition 项,跳过失败项但记录错误。
|
|
:param request:
|
|
:param updated_contents:
|
|
:param admin_user:
|
|
:return:
|
|
"""
|
|
|
|
if not admin_user[0].is_admin:
|
|
raise HTTPException(status_code=403, detail="非管理员,无权限访问")
|
|
|
|
if updated_contents.count() == 0:
|
|
raise HTTPException(status_code=422, detail="无改动信息")
|
|
|
|
errors = []
|
|
|
|
async def update_definition(update_word: UpdateWord) -> None:
|
|
# 检查词条是否存在
|
|
if update_word.language == 'fr':
|
|
word_entry = await fr.WordlistFr.get_or_none(id=update_word.id)
|
|
if not word_entry:
|
|
raise HTTPException(status_code=400, detail=f"词条 ID {update_word.id} 不存在于法语词表中")
|
|
update_obj = await fr.DefinitionFr.get_or_none(id=update_word.id)
|
|
else:
|
|
word_entry = await jp.WordlistJp.get_or_none(id=update_word.id)
|
|
if not word_entry:
|
|
raise HTTPException(status_code=400, detail=f"词条 ID {update_word.id} 不存在于日语词表中")
|
|
update_obj = await jp.DefinitionJp.get_or_none(id=update_word.id)
|
|
|
|
if not update_obj:
|
|
raise HTTPException(status_code=404, detail=f"定义 ID {update_word.id} 不存在")
|
|
|
|
# 获取更新字段
|
|
update_data = update_word.model_dump(exclude_unset=True)
|
|
|
|
for field, value in update_data.items():
|
|
if field != "id":
|
|
setattr(update_obj, field, value)
|
|
|
|
await update_obj.save()
|
|
|
|
for updated_content in updated_contents:
|
|
try:
|
|
await update_definition(updated_content)
|
|
except HTTPException as e:
|
|
errors.append({
|
|
"id": updated_content.id,
|
|
"error": e.detail
|
|
})
|
|
|
|
return {
|
|
"msg": "更新完成",
|
|
"success_count": updated_contents.count() - len(errors),
|
|
"fail_count": len(errors),
|
|
"errors": errors
|
|
}
|
|
|
|
|
|
@admin_router.post("/dict/add")
|
|
async def add_dict(
|
|
request: Request,
|
|
new_word: CreateWord,
|
|
admin_user: Tuple[User, dict] = Depends(get_current_user)
|
|
) -> None:
|
|
if not admin_user[0].is_admin:
|
|
raise HTTPException(status_code=403, detail="非管理员,无权限访问")
|
|
if new_word.language == "fr":
|
|
cls_word, _ = await fr.WordlistFr.get_or_create(text=new_word.word)
|
|
new_definition, created = await fr.DefinitionFr.get_or_create(
|
|
word=cls_word,
|
|
pos=new_word.pos,
|
|
meaning=new_word.meaning,
|
|
example=new_word.example,
|
|
eng_explanation=new_word.eng_explanation
|
|
)
|
|
if not created:
|
|
raise HTTPException(status_code=409, detail="释义已存在")
|
|
elif new_word.language == "jp":
|
|
cls_word, _ = await jp.WordlistJp.get_or_create(text=new_word.word)
|
|
new_definition, created = await jp.DefinitionJp.get_or_create(
|
|
word=cls_word,
|
|
pos=new_word.pos,
|
|
meaning=new_word.meaning,
|
|
example=new_word.example,
|
|
)
|
|
if not created:
|
|
raise HTTPException(status_code=409, detail="释义已存在")
|
|
else:
|
|
raise HTTPException(status_code=400, detail="暂不支持语言类型")
|