| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860 |
- """
- 企业管理员代理路由
- 把订单、消费、发票、审核、日志、模型等模块代理到企业管理员认证,
- 并在 service 层加 tenant_id 过滤。
- """
- from typing import Optional
- from datetime import date
- from fastapi import APIRouter, Depends, HTTPException, Query, Request, status
- from sqlalchemy.orm import Session
- from app.database import get_db
- from app.dependencies.enterprise_auth import get_current_enterprise_admin
- from app.models.tenant import EnterpriseAdmin
- from app.models.user import User
- router = APIRouter(prefix="/api/enterprise-admin", tags=["企业管理员-代理"])
- def _tenant_user_ids(db: Session, tenant_id: int):
- return db.query(User.id).filter(User.tenant_id == tenant_id).all()
- # ==================== 订单管理 ====================
- @router.get("/orders")
- def list_orders(
- keyword: str = Query(None), status_filter: str = Query(None, alias="status"),
- payment_method: str = Query(None), start_date: str = Query(None),
- end_date: str = Query(None), amount_min: float = Query(None),
- amount_max: float = Query(None), sort_by: str = Query("created_at"),
- sort_order: str = Query("desc"), page: int = Query(1, ge=1),
- size: int = Query(20, ge=1, le=100),
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- from app.services.admin_order_service import AdminOrderService, AdminOrderException
- from app.schemas.admin_order_schema import OrderListParams
- params = OrderListParams(
- keyword=keyword, status=status_filter, payment_method=payment_method,
- start_date=start_date, end_date=end_date, amount_min=amount_min,
- amount_max=amount_max, sort_by=sort_by, sort_order=sort_order,
- page=page, size=size
- )
- service = AdminOrderService(db)
- orders, total = service.list_orders(params, tenant_id=current_admin.tenant_id)
- return {"code": 0, "message": "success", "data": {
- "items": [o.model_dump() for o in orders],
- "total": total, "page": page, "size": size,
- "pages": (total + size - 1) // size
- }}
- @router.get("/orders/export")
- def export_orders(
- keyword: str = Query(None), status_filter: str = Query(None, alias="status"),
- start_date: str = Query(None), end_date: str = Query(None),
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- from app.services.admin_order_service import AdminOrderService
- from app.schemas.admin_order_schema import OrderListParams
- params = OrderListParams(keyword=keyword, status=status_filter,
- start_date=start_date, end_date=end_date, page=1, size=10000)
- service = AdminOrderService(db)
- url = service.export_orders(params)
- return {"code": 0, "data": {"download_url": url}}
- @router.get("/orders/{order_id}")
- def get_order_detail(
- order_id: int,
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- from app.services.admin_order_service import AdminOrderService, AdminOrderException
- service = AdminOrderService(db)
- order = service.get_order_detail(order_id)
- # 验证订单属于本企业
- user = db.query(User).filter(User.id == order.user_id, User.tenant_id == current_admin.tenant_id).first()
- if not user:
- raise HTTPException(status_code=404, detail={"code": "NOT_FOUND", "message": "订单不存在"})
- return {"code": 0, "data": order.model_dump()}
- @router.post("/orders/{order_id}/confirm")
- def confirm_order(
- order_id: int, data: dict, request: Request,
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- from app.services.admin_order_service import AdminOrderService
- service = AdminOrderService(db)
- service.confirm_order(order_id, current_admin.id, data.get("reason", ""), request.client.host if request.client else "")
- return {"code": 0, "message": "确认成功"}
- @router.post("/orders/{order_id}/refund")
- def refund_order(
- order_id: int, data: dict, request: Request,
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- from app.services.admin_order_service import AdminOrderService
- service = AdminOrderService(db)
- service.refund_order(order_id, current_admin.id, data.get("reason", ""), request.client.host if request.client else "")
- return {"code": 0, "message": "退款成功"}
- # ==================== 账单管理 ====================
- @router.get("/bills")
- def list_bills(
- keyword: str = Query(None), biz_type: str = Query(None),
- module: str = Query(None), start_date: str = Query(None),
- end_date: str = Query(None), sort_by: str = Query("created_at"),
- sort_order: str = Query("desc"), page: int = Query(1, ge=1),
- size: int = Query(20, ge=1, le=100),
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- from app.services.admin_bill_service import AdminBillService
- from app.schemas.admin_order_schema import BillListParams
- params = BillListParams(keyword=keyword, biz_type=biz_type, module=module,
- start_date=start_date, end_date=end_date, sort_by=sort_by,
- sort_order=sort_order, page=page, size=size)
- service = AdminBillService(db)
- bills, total = service.list_bills(params, tenant_id=current_admin.tenant_id)
- return {"code": 0, "data": {
- "items": [b.model_dump() for b in bills],
- "total": total, "page": page, "size": size,
- "pages": (total + size - 1) // size
- }}
- # ==================== 消费记录 ====================
- @router.get("/consumptions")
- def list_consumptions(
- user_id: str = Query(None), order_no: str = Query(None),
- model_name: str = Query(None), start_date: date = Query(None),
- end_date: date = Query(None), invoiced: bool = Query(None),
- page: int = Query(1, ge=1), size: int = Query(20, ge=1, le=100),
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- from app.services.admin_consumption_service import AdminConsumptionService
- from app.schemas.admin_consumption_invoice_schema import ConsumptionListParams
- params = ConsumptionListParams(user_id=user_id, order_no=order_no,
- model_name=model_name, start_date=start_date, end_date=end_date,
- invoiced=invoiced, page=page, size=size)
- service = AdminConsumptionService(db)
- items, total = service.list_consumptions(params, tenant_id=current_admin.tenant_id)
- return {"code": 0, "data": {
- "items": [i.model_dump() for i in items],
- "total": total, "page": page, "size": size,
- "pages": (total + size - 1) // size
- }}
- # ==================== 发票管理 ====================
- @router.get("/invoices")
- def list_invoices(
- user_id: str = Query(None), inv_status: str = Query(None, alias="status"),
- invoice_type: str = Query(None), start_date: date = Query(None),
- end_date: date = Query(None), page: int = Query(1, ge=1),
- size: int = Query(20, ge=1, le=100),
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- from app.services.admin_invoice_service import AdminInvoiceService
- from app.schemas.admin_consumption_invoice_schema import InvoiceListParams
- params = InvoiceListParams(user_id=user_id, status=inv_status,
- invoice_type=invoice_type, start_date=start_date, end_date=end_date,
- page=page, size=size)
- service = AdminInvoiceService(db)
- items, total = service.list_invoices(params, tenant_id=current_admin.tenant_id)
- return {"code": 0, "data": {
- "items": [i.model_dump() for i in items],
- "total": total, "page": page, "size": size,
- "pages": (total + size - 1) // size
- }}
- @router.get("/invoices/{invoice_id}")
- def get_invoice_detail(
- invoice_id: int,
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- from app.services.admin_invoice_service import AdminInvoiceService
- service = AdminInvoiceService(db)
- detail = service.get_invoice_detail(invoice_id)
- return {"code": 0, "data": detail.model_dump()}
- @router.post("/invoices/{invoice_id}/approve")
- def approve_invoice(
- invoice_id: int, request: Request,
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- from app.services.admin_invoice_service import AdminInvoiceService
- service = AdminInvoiceService(db)
- service.approve_invoice(invoice_id, current_admin.id, request.client.host if request.client else "")
- return {"code": 0, "message": "审核通过"}
- @router.post("/invoices/{invoice_id}/reject")
- def reject_invoice(
- invoice_id: int, data: dict, request: Request,
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- from app.services.admin_invoice_service import AdminInvoiceService
- service = AdminInvoiceService(db)
- service.reject_invoice(invoice_id, current_admin.id, data.get("reason", ""), request.client.host if request.client else "")
- return {"code": 0, "message": "驳回成功"}
- # ==================== 内容审核 ====================
- @router.get("/review/pictures")
- def get_pictures(
- rev_status: str = Query(None, alias="status"), page: int = Query(1, ge=1),
- size: int = Query(20, ge=1, le=100),
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- from app.services.review_service import ReviewService
- service = ReviewService(db)
- result = service.get_picture_review_list(rev_status, None, None, None, page, size,
- tenant_id=current_admin.tenant_id)
- return {"code": 0, "data": result}
- @router.get("/review/videos")
- def get_videos(
- rev_status: str = Query(None, alias="status"), page: int = Query(1, ge=1),
- size: int = Query(20, ge=1, le=100),
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- from app.services.review_service import ReviewService
- service = ReviewService(db)
- result = service.get_video_review_list(rev_status, None, None, None, page, size,
- tenant_id=current_admin.tenant_id)
- return {"code": 0, "data": result}
- @router.get("/review/audios")
- def get_audios(
- rev_status: str = Query(None, alias="status"), page: int = Query(1, ge=1),
- size: int = Query(20, ge=1, le=100),
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- from app.services.review_service import ReviewService
- service = ReviewService(db)
- result = service.get_audio_review_list(rev_status, None, None, None, page, size,
- tenant_id=current_admin.tenant_id)
- return {"code": 0, "data": result}
- @router.post("/review/{content_type}/{content_id}/approve")
- def approve_content(
- content_type: str, content_id: int, action: dict = {},
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- from app.services.review_service import ReviewService
- service = ReviewService(db)
- service.approve_content(content_type, content_id, current_admin.id, action.get("remark"))
- return {"code": 0, "message": "审核通过"}
- @router.post("/review/{content_type}/{content_id}/reject")
- def reject_content(
- content_type: str, content_id: int, action: dict,
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- from app.services.review_service import ReviewService
- service = ReviewService(db)
- service.reject_content(content_type, content_id, current_admin.id,
- action.get("reason", ""), action.get("delete_content", False), action.get("ban_user", False))
- return {"code": 0, "message": "审核拒绝"}
- # ==================== 日志审计 ====================
- @router.get("/logs/api")
- def list_api_logs(
- user_id: str = Query(None), username: str = Query(None),
- phone: str = Query(None), module: str = Query(None),
- api_path: str = Query(None), start_date: str = Query(None),
- end_date: str = Query(None), page: int = Query(1, ge=1),
- size: int = Query(20, ge=1, le=100),
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- from app.services.log_service import LogService
- service = LogService(db)
- result = service.get_api_logs(start_date=start_date, end_date=end_date,
- user_id=user_id, username=username, phone=phone, module=module,
- api_path=api_path, page=page, size=size, tenant_id=current_admin.tenant_id)
- return {"code": 0, "data": result}
- @router.get("/logs/logins")
- def list_login_logs(
- user_type: str = Query(None), login_result: str = Query(None),
- start_date: str = Query(None), end_date: str = Query(None),
- page: int = Query(1, ge=1), size: int = Query(20, ge=1, le=100),
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- from app.services.log_service import LogService
- service = LogService(db)
- result = service.get_login_logs(start_date=start_date, end_date=end_date,
- user_type=user_type, login_result=login_result, page=page, size=size,
- tenant_id=current_admin.tenant_id)
- return {"code": 0, "data": result}
- # ==================== 模型管理(只读,不隔离) ====================
- @router.get("/models")
- def list_models(
- keyword: str = Query(None), category: str = Query(None),
- is_show_enabled: bool = Query(None), page: int = Query(1, ge=1),
- size: int = Query(20, ge=1, le=100),
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- from app.services.admin_model_service import AdminModelService
- from app.schemas.admin_schema import ModelListParams
- params = ModelListParams(keyword=keyword, category=category,
- is_show_enabled=is_show_enabled, page=page, size=size)
- service = AdminModelService(db)
- models, total = service.list_models(params)
- return {"code": 0, "data": {
- "items": [m.model_dump() for m in models],
- "total": total, "page": page, "size": size
- }}
- @router.get("/models/local")
- def list_local_models(
- keyword: str = Query(None), page: int = Query(1, ge=1),
- size: int = Query(20, ge=1, le=100),
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- from app.models.model import ModelNew
- from app.models.tenant import Tenant
- from sqlalchemy import or_, desc
- # 检查企业是否开启了私域模型功能
- tenant = db.query(Tenant).filter(Tenant.id == current_admin.tenant_id).first()
- if tenant and not getattr(tenant, "enable_local_model", True):
- raise HTTPException(status_code=403, detail="该企业未开启私域模型功能")
- query = db.query(ModelNew).filter(
- ModelNew.is_local == True,
- ModelNew.tenant_id == current_admin.tenant_id
- )
- if keyword:
- kw = f"%{keyword}%"
- query = query.filter(or_(ModelNew.model_code.ilike(kw), ModelNew.display_name.ilike(kw)))
- total = query.count()
- models = query.order_by(desc(ModelNew.created_at)).offset((page - 1) * size).limit(size).all()
- items = [{"id": m.id, "model_code": m.model_code, "title": m.display_name,
- "visibility": m.visibility, "user_id": m.user_id, "tenant_id": m.tenant_id,
- "created_at": m.created_at.isoformat() if m.created_at else None} for m in models]
- return {"code": 0, "data": {"items": items, "total": total, "page": page, "size": size}}
- # ==================== 系统配置 ====================
- @router.get("/config/branding")
- def get_branding_config(
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- """获取品牌配置,优先返回企业自己设置的值,没有则 fallback 到全局默认"""
- from app.models.config import SystemConfig
- import json as _json
- KEYS = ["system_name", "system_logo", "icp_number"]
- DEFAULTS = {"system_name": "智创空间", "system_logo": "", "icp_number": ""}
- result = {}
- for key in KEYS:
- # 先查企业自己的配置
- row = db.query(SystemConfig).filter(
- SystemConfig.tenant_id == current_admin.tenant_id,
- SystemConfig.config_key == key
- ).first()
- if row:
- try:
- result[key] = _json.loads(row.config_value)
- except Exception:
- result[key] = row.config_value
- continue
- # fallback 到全局
- row = db.query(SystemConfig).filter(
- SystemConfig.tenant_id == None,
- SystemConfig.config_key == key
- ).first()
- if row:
- try:
- result[key] = _json.loads(row.config_value)
- except Exception:
- result[key] = row.config_value
- else:
- result[key] = DEFAULTS[key]
- return {"code": 0, "data": result}
- @router.get("/config")
- def get_config(
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- from app.services.config_service import ConfigService
- service = ConfigService(db, tenant_id=current_admin.tenant_id)
- return service.get_all_configs()
- @router.put("/config")
- def update_config(
- update_data: dict,
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- from app.services.config_service import ConfigService
- from app.schemas.config_schema import ConfigUpdate
- service = ConfigService(db, tenant_id=current_admin.tenant_id)
- configs = [ConfigUpdate(**c) for c in update_data.get("configs", [])]
- service.update_configs(configs, current_admin.id)
- return {"message": "配置更新成功", "data": None}
- @router.get("/config/{config_key}/history")
- def get_config_history(
- config_key: str,
- page: int = Query(1, ge=1),
- size: int = Query(20, ge=1, le=100),
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- from app.services.config_service import ConfigService
- service = ConfigService(db, tenant_id=current_admin.tenant_id)
- history = service.get_config_history(config_key, page, size)
- return {"data": history}
- @router.post("/config/{config_key}/reset")
- def reset_config(
- config_key: str,
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- from app.services.config_service import ConfigService
- service = ConfigService(db, tenant_id=current_admin.tenant_id)
- service.reset_config(config_key, current_admin.id)
- return {"message": "配置重置成功", "data": None}
- @router.get("/local-config")
- def get_local_config(
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- ):
- from app.services import local_config_service
- from app.schemas.local_config_schema import LocalConfigResponse
- result = local_config_service.get_all()
- return LocalConfigResponse(data=result)
- # ==================== 模型写操作 ====================
- @router.post("/models")
- def create_model(
- data: dict,
- request: Request,
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- from app.services.admin_model_service import AdminModelService
- from app.schemas.admin_schema import ModelCreateRequest
- service = AdminModelService(db)
- req = ModelCreateRequest(**data)
- model_id = service.create_model(req)
- return {"message": "模型创建成功", "model_id": model_id}
- @router.put("/models/{model_id}")
- def update_model(
- model_id: int,
- data: dict,
- request: Request,
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- from app.services.admin_model_service import AdminModelService
- from app.schemas.admin_schema import ModelUpdateRequest
- service = AdminModelService(db)
- req = ModelUpdateRequest(**data)
- service.update_model(model_id, req)
- return {"message": "模型更新成功", "model_id": model_id}
- @router.put("/models/{model_id}/price")
- def update_model_price(
- model_id: int,
- data: dict,
- request: Request,
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- from app.services.admin_model_service import AdminModelService
- from app.schemas.admin_schema import ModelPriceRequest
- service = AdminModelService(db)
- req = ModelPriceRequest(**data)
- service.update_model_price(model_id, req)
- return {"message": "价格更新成功", "model_id": model_id}
- @router.put("/models/{model_id}/status")
- def update_model_status(
- model_id: int,
- data: dict,
- request: Request,
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- from app.services.admin_model_service import AdminModelService
- from app.schemas.admin_schema import ModelStatusRequest
- service = AdminModelService(db)
- req = ModelStatusRequest(**data)
- service.update_model_status(model_id, req.field, req.value)
- return {"message": "状态更新成功", "model_id": model_id, req.field: req.value}
- # ==================== 企业私域模型创建/删除/测试 ====================
- @router.post("/models/local/test")
- async def test_local_model_connection(
- data: dict,
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- """企业管理员测试私域模型连接"""
- from app.services.local_model_service import LocalModelService
- from app.schemas.local_model import ConnectionTestRequest
- service = LocalModelService(db)
- categories = data.get('categories') or [0]
- result = await service.test_connection(
- data.get('base_url', ''),
- data.get('api_key'),
- data.get('model_name'),
- categories[0] if categories else 0,
- )
- return result
- @router.put("/models/local/{model_id}")
- async def update_local_model(
- model_id: int,
- data: dict,
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- """企业管理员更新本企业私域模型"""
- from app.models.model import ModelNew
- from app.services.crypto_utils import encrypt_api_key
- model = db.query(ModelNew).filter(
- ModelNew.id == model_id,
- ModelNew.is_local == True,
- ModelNew.tenant_id == current_admin.tenant_id,
- ).first()
- if not model:
- raise HTTPException(status_code=404, detail="模型不存在")
- if 'name' in data:
- model.display_name = data['name']
- if 'supplier' in data:
- model.supplier = data['supplier']
- if 'base_url' in data:
- model.base_url = data['base_url']
- if 'api_key' in data and data['api_key']:
- model.local_api_key = encrypt_api_key(data['api_key'])
- if 'categories' in data:
- model.categories = data['categories']
- if 'visibility' in data:
- model.visibility = data['visibility']
- db.commit()
- return {"code": 0, "message": "更新成功"}
- @router.post("/models/local")
- async def create_local_model(
- data: dict,
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- """企业管理员创建私域模型,自动绑定 tenant_id"""
- from app.services.local_model_service import LocalModelService
- import time
- from app.models.model import ModelNew
- from app.models.tenant import Tenant
- from app.services.crypto_utils import encrypt_api_key
- # 检查企业是否开启了私域模型功能
- tenant = db.query(Tenant).filter(Tenant.id == current_admin.tenant_id).first()
- if tenant and not getattr(tenant, "enable_local_model", True):
- raise HTTPException(status_code=403, detail="该企业未开启私域模型功能")
- base_url = data.get('base_url', '')
- if not base_url:
- raise HTTPException(status_code=400, detail="base_url 不能为空")
- service = LocalModelService(db)
- is_valid, err = service.validate_base_url(base_url)
- if not is_valid:
- raise HTTPException(status_code=400, detail=err)
- api_key = data.get('api_key')
- model_code = f"local_tenant_{current_admin.tenant_id}_{int(time.time() * 1000)}"
- model = ModelNew(
- model_code=model_code,
- display_name=data.get('name', model_code),
- supplier=data.get('supplier', 'Custom'),
- img="",
- categories=data.get('categories', [0]),
- is_local=True,
- user_id=None,
- tenant_id=current_admin.tenant_id,
- base_url=base_url,
- local_api_key=encrypt_api_key(api_key) if api_key else None,
- is_show_enabled=False,
- is_api_enabled=True,
- visibility=data.get('visibility', 'global'),
- )
- db.add(model)
- db.commit()
- db.refresh(model)
- return {"code": 0, "message": "创建成功", "data": {"id": model.id, "model_code": model.model_code}}
- @router.delete("/models/local/{model_id}")
- def delete_enterprise_local_model(
- model_id: int,
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- """企业管理员删除本企业的私域模型"""
- from app.models.model import ModelNew
- model = db.query(ModelNew).filter(
- ModelNew.id == model_id,
- ModelNew.is_local == True,
- ModelNew.tenant_id == current_admin.tenant_id
- ).first()
- if not model:
- raise HTTPException(status_code=404, detail="模型不存在或无权限")
- db.delete(model)
- db.commit()
- return {"code": 0, "message": "删除成功"}
- # ==================== 本地模型写操作 ====================
- @router.put("/local-models/{model_id}/visibility")
- def update_local_model_visibility(
- model_id: int,
- data: dict,
- request: Request,
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- from app.models.model import ModelNew
- model = db.query(ModelNew).filter(ModelNew.id == model_id, ModelNew.is_local == True).first()
- if not model:
- raise HTTPException(status_code=404, detail="本地模型不存在")
- model.visibility = data.get("visibility", model.visibility)
- db.commit()
- return {"message": "可见性更新成功", "model_id": model_id, "visibility": model.visibility}
- @router.delete("/local-models/{model_id}")
- def delete_local_model(
- model_id: int,
- request: Request,
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- from app.models.model import ModelNew
- model = db.query(ModelNew).filter(ModelNew.id == model_id, ModelNew.is_local == True).first()
- if not model:
- raise HTTPException(status_code=404, detail="本地模型不存在")
- db.delete(model)
- db.commit()
- return {"message": "本地模型已删除", "model_id": model_id}
- # ==================== 用户本地模型权限 ====================
- @router.get("/users/{user_id}/local-model-permissions")
- def get_user_local_model_permissions(
- user_id: str,
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- from app.services.user_local_model_permission_service import UserLocalModelPermissionService
- service = UserLocalModelPermissionService(db)
- return service.get_user_model_permissions(user_id)
- @router.put("/users/{user_id}/local-model-permissions/{model_id}")
- async def update_user_local_model_permission(
- user_id: str,
- model_id: int,
- data: dict,
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- from app.services.user_local_model_permission_service import UserLocalModelPermissionService
- service = UserLocalModelPermissionService(db)
- success = await service.update_user_model_permission(
- user_id=user_id, model_id=model_id, has_access=data.get("has_access", False)
- )
- if not success:
- raise HTTPException(status_code=400, detail="更新权限失败")
- return {"message": "权限更新成功"}
- @router.put("/users/{user_id}/local-model-permissions")
- async def update_user_all_local_model_permissions(
- user_id: str,
- data: dict,
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- from app.services.user_local_model_permission_service import UserLocalModelPermissionService
- service = UserLocalModelPermissionService(db)
- success = await service.update_user_all_model_permissions(
- user_id=user_id, has_access=data.get("has_access", False)
- )
- if not success:
- raise HTTPException(status_code=400, detail="更新权限失败")
- return {"message": "权限更新成功"}
- # ==================== 统计导出 ====================
- @router.get("/stats/users/export")
- async def export_user_stats(
- start_date: date = Query(...),
- end_date: date = Query(...),
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- from app.services.admin_stats_service import AdminStatsService
- service = AdminStatsService(db)
- file_url = await service.export_user_stats(start_date, end_date)
- return {"file_url": file_url}
- @router.get("/stats/revenue/export")
- async def export_revenue_stats(
- start_date: date = Query(...),
- end_date: date = Query(...),
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- from app.services.admin_stats_service import AdminStatsService
- service = AdminStatsService(db)
- file_url = await service.export_revenue_stats(start_date, end_date)
- return {"file_url": file_url}
- @router.get("/stats/business/export")
- async def export_business_stats(
- start_date: date = Query(...),
- end_date: date = Query(...),
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db)
- ):
- from app.services.admin_stats_service import AdminStatsService
- service = AdminStatsService(db)
- file_url = await service.export_business_stats(start_date, end_date)
- return {"file_url": file_url}
- # ── 企业流水(租户隔离)────────────────────────────────────────────────────────
- from app.models.tenant import TenantBalanceLog
- from sqlalchemy import desc as _desc_tbl
- from datetime import datetime, time as _time
- @router.get("/balance-logs")
- def list_tenant_balance_logs(
- biz_type: str = Query(None, description="recharge/consume/adjust"),
- start_date: date = Query(None),
- end_date: date = Query(None),
- page: int = Query(1, ge=1),
- size: int = Query(20, ge=1, le=100),
- current_admin: EnterpriseAdmin = Depends(get_current_enterprise_admin),
- db: Session = Depends(get_db),
- ):
- """查询本企业余额流水(租户隔离)"""
- tenant_id = current_admin.tenant_id
- q = db.query(TenantBalanceLog).filter(TenantBalanceLog.tenant_id == tenant_id)
- if biz_type:
- q = q.filter(TenantBalanceLog.biz_type == biz_type)
- if start_date:
- q = q.filter(TenantBalanceLog.created_at >= datetime.combine(start_date, _time.min))
- if end_date:
- q = q.filter(TenantBalanceLog.created_at <= datetime.combine(end_date, _time.max))
- total = q.count()
- logs = q.order_by(_desc_tbl(TenantBalanceLog.created_at)).offset((page - 1) * size).limit(size).all()
- items = [
- {
- "id": l.id,
- "change_amount": float(l.change_amount),
- "balance_after": float(l.balance_after),
- "biz_type": l.biz_type,
- "biz_order_no": l.biz_order_no,
- "remark": l.remark,
- "created_at": l.created_at.isoformat() if l.created_at else None,
- }
- for l in logs
- ]
- # 累计统计(不受分页影响,基于当前筛选条件)
- from sqlalchemy import func as _func
- stats_q = db.query(TenantBalanceLog).filter(TenantBalanceLog.tenant_id == tenant_id)
- if biz_type:
- stats_q = stats_q.filter(TenantBalanceLog.biz_type == biz_type)
- if start_date:
- stats_q = stats_q.filter(TenantBalanceLog.created_at >= datetime.combine(start_date, _time.min))
- if end_date:
- stats_q = stats_q.filter(TenantBalanceLog.created_at <= datetime.combine(end_date, _time.max))
- total_recharge = float(stats_q.filter(TenantBalanceLog.change_amount > 0)
- .with_entities(_func.sum(TenantBalanceLog.change_amount)).scalar() or 0)
- total_consume = float(stats_q.filter(TenantBalanceLog.change_amount < 0)
- .with_entities(_func.sum(TenantBalanceLog.change_amount)).scalar() or 0)
- return {
- "items": items, "total": total, "page": page, "size": size,
- "total_recharge": total_recharge,
- "total_consume": total_consume,
- }
|