from fastapi import APIRouter, Request, Depends, Form from fastapi.responses import HTMLResponse from sqlalchemy.orm import Session from sqlalchemy import text from database import SessionLocal, redis_client from services.template_service import build_template from services.price_service import apply_adjust import json import uuid router = APIRouter(prefix="/estimate", tags=["estimate"]) # ================= DB ================= def get_db(): db = SessionLocal() try: yield db finally: db.close() # ================= 获取所有机型 ================= @router.get("/simulate", response_class=HTMLResponse) def simulate(db: Session = Depends(get_db)): # 获取所有有模板的机型 machines = db.execute(text(""" SELECT machine_id, name FROM t_machine WHERE machine_id IN (SELECT DISTINCT machine_id FROM machine_temp) """)).fetchall() html = "

估价模拟

" html += '
' # 展示机型选择 html += '
' html += '
' html += '
' return html # ================= 获取机型模板和选项 ================= @router.get("/simulate_one", response_class=HTMLResponse) def simulate( machine_id: int, db: Session = Depends(get_db) ): # 获取机型对应的模板 row = db.execute(text(""" SELECT estimate_packet FROM machine_temp WHERE machine_id=:mid """), {"mid": machine_id}).fetchone() tpl = json.loads(row.estimate_packet) html = f"

估价模拟 - {tpl['templateId']}

" html += '
' for step in tpl["template"]: html += f"

{step['stepName']}

" for p in step["properties"]: html += f"{p['name']}
" for v in p["values"]: html += f"""
""" html += f"""
""" return html # ================= 提交估价并计算价格 ================= @router.post("/simulate", response_class=HTMLResponse) def simulate_calc( machine_id: int = Form(...), option_ids: list[str] = Form([]), db: Session = Depends(get_db) ): # 获取基准价格 base_price_row = db.execute(text(""" SELECT base_price FROM machine_base_price WHERE machine_id=:mid """), {"mid": machine_id}).fetchone() # base_price = base_price_row.base_price base_price = base_price_row.base_price if base_price_row else 1000.0 # 获取选项因素 factors = db.execute(text(""" SELECT option_id, factor, absolute_deduct FROM price_option_factor WHERE option_id IN :ids """), {"ids": tuple(option_ids)}).fetchall() # 计算价格 price = base_price for f in factors: if f.factor: price *= float(f.factor) if f.absolute_deduct: price -= float(f.absolute_deduct) # 逐步应用调节因子 # 1. 获取全局调节因子 global_adjust = db.execute(text(""" SELECT factor FROM price_adjust_factor WHERE level='global' """)).fetchone() if global_adjust: price *= float(global_adjust.factor) # 2. 获取品牌调节因子 brand_adjust = db.execute(text(""" SELECT factor FROM price_adjust_factor WHERE level='brand' AND ref_id=( SELECT brand_id FROM t_machine WHERE machine_id=:mid ) """), {"mid": machine_id}).fetchone() if brand_adjust: price *= float(brand_adjust.factor) # 3. 获取机型调节因子 machine_adjust = db.execute(text(""" SELECT factor FROM price_adjust_factor WHERE level='machine' AND ref_id=:mid """), {"mid": machine_id}).fetchone() if machine_adjust: price *= float(machine_adjust.factor) html = f"""

估价结果

选择项:{",".join(option_ids)}
估价:{round(price, 2)} 元
返回 """ return html @router.post("/estimate2", response_class=HTMLResponse) def estimate_submit( request: Request, machine_id: int = Form(...), capacity: str = Form(...), option_ids: list[int] = Form([]), db: Session = Depends(get_db) ): # ---------- 基础价格 ---------- base_price = db.execute( text(""" SELECT base_price FROM machine_base_price WHERE machine_id=:mid AND capacity=:cap """), {"mid": machine_id, "cap": capacity} ).scalar() or 0 price = float(base_price) # ---------- 扣减项 ---------- for oid in option_ids: r = db.execute( text(""" SELECT factor, absolute_deduct FROM price_option_factor WHERE option_id=:oid """), {"oid": oid} ).fetchone() if r: price = price * float(r.factor) - float(r.absolute_deduct) # ---------- 调节系数 ---------- brand_id = db.execute( text(""" SELECT brand_id FROM t_machine WHERE machine_id=:mid """), {"mid": machine_id} ).scalar() price = apply_adjust(db, machine_id, brand_id, price) price = round(max(price, 0), 2) # ---------- 估价版本 ---------- version_no = str(uuid.uuid4())[:8] db.execute( text(""" INSERT INTO estimate_record (machine_id, capacity, option_ids, final_price, version_no) VALUES (:m, :c, :o, :p, :v) """), { "m": machine_id, "c": capacity, "o": ",".join(map(str, option_ids)), "p": price, "v": version_no } ) db.commit() # ---------- 模板(Redis 缓存) ---------- cache_key = f"template:{machine_id}" cached = redis_client.get(cache_key) if redis_client else None if cached: template = json.loads(cached) else: rows = db.execute(text("SELECT * FROM release_option")).fetchall() template = build_template(rows) if redis_client: redis_client.set(cache_key, json.dumps(template), ex=3600) # ---------- 重新加载页面 ---------- machines = db.execute( text(""" SELECT machine_id, name FROM t_machine ORDER BY brand_name, name """) ).fetchall() capacities = db.execute( text(""" SELECT capacity FROM machine_base_price WHERE machine_id=:mid """), {"mid": machine_id} ).fetchall() return request.app.state.templates.TemplateResponse( "estimate.html", { "request": request, "machines": machines, "capacities": capacities, "template": template, "price": price, "version": version_no, "selected_machine": machine_id, "selected_capacity": capacity } )