from fastapi import APIRouter, Request, Depends, Form
from fastapi.responses import HTMLResponse, RedirectResponse
from sqlalchemy import text # 新增这一行
from sqlalchemy.orm import Session
from database import SessionLocal
import json
import time
from datetime import datetime
from datetime import datetime
from services.template_builder import build_estimate_template
router = APIRouter(prefix="/admin", tags=["admin"])
# ---------- DB ----------
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
# ---------- 机型管理 ----------
@router.get("/machines", response_class=HTMLResponse)
def machine_page(db: Session = Depends(get_db)):
categories = db.execute(text("""
SELECT category_id, name FROM t_chx_category
""")).fetchall()
machines = db.execute(text("""
SELECT brand_name, name, type_name
FROM t_machine
ORDER BY id DESC
LIMIT 50
""")).fetchall()
html = """
机型管理
"""
for m in machines:
html += f"- {m.type_name} | {m.brand_name} - {m.name}
"
html += "
"
return html
@router.post("/machines/add")
def add_machine(
type_id: int = Form(...),
brand_name: str = Form(...),
machine_name: str = Form(...),
db: Session = Depends(get_db)
):
category = db.execute(
text("SELECT name FROM t_chx_category WHERE category_id=:id"),
{"id": type_id}
).fetchone()
machine_id = int(time.time() * 1000)
brand_id = int(time.time() * 1000)
db.execute(text("""
INSERT INTO t_machine
(
code,
type_id,
type_name,
brand_id,
brand_name,
machine_id,
name,
create_time
)
VALUES
(
'mobile',
:type_id,
:type_name,
:brand_id,
:brand_name,
:machine_id,
:name,
:time
)
"""), {
"type_id": type_id,
"type_name": category.name,
"brand_id": brand_id,
"brand_name": brand_name,
"machine_id": machine_id,
"name": machine_name,
"time": datetime.now()
})
db.commit()
return RedirectResponse("/admin/machines", status_code=302)
# ---------- release_option 管理 ----------
@router.get("/options", response_class=HTMLResponse)
def option_page(db: Session = Depends(get_db)):
rows = db.execute(text("""
SELECT step_name, option_key_name, option_name
FROM release_option
ORDER BY step_name, option_key_name
""")).fetchall()
# 组装树
tree = {}
for r in rows:
step = r.step_name
key = r.option_key_name
opt = r.option_name
tree.setdefault(step, {})
if key:
tree[step].setdefault(key, [])
if opt:
tree[step][key].append(opt)
# 渲染 HTML
html = "检测项管理
"
for step, keys in tree.items():
html += f"📂 {step}
"
for key, opts in keys.items():
html += f"- 📁 {key}
"
for o in opts:
html += f"- ✅ {o}
"
html += "
"
html += "
"
# 表单
html += """
➕ 新增父级
➕ 新增子级
➕ 新增选项
"""
return html
@router.post("/options/add")
def add_option(
step_name: str = Form(...),
option_key_name: str = Form(""),
option_name: str = Form(""),
db: Session = Depends(get_db)
):
db.execute(text("""
INSERT INTO release_option
(step_id, step_name, option_key_id, option_key_name, option_id, option_name)
VALUES
(
2,
:step,
UNIX_TIMESTAMP(),
:key,
UNIX_TIMESTAMP(),
:opt
)
"""), {
"step": step_name,
"key": option_key_name,
"opt": option_name
})
db.commit()
return RedirectResponse("/admin/options", status_code=302)
# ---------- API ----------
@router.get("/capacities/{machine_id}")
def capacities(machine_id: int, db: Session = Depends(get_db)):
return db.execute(
"SELECT capacity FROM machine_base_price WHERE machine_id=:id",
{"id": machine_id}
).fetchall()
@router.post("/release_option/add")
def add_option(
step_id: int = Form(...),
step_name: str = Form(...),
option_key_name: str = Form(...),
option_name: str = Form(...),
db: Session = Depends(get_db)
):
db.execute("""
INSERT INTO release_option(step_id,step_name,option_key_id,option_key_name,option_id,option_name)
VALUES (:sid,:sname, UNIX_TIMESTAMP(), :kname, UNIX_TIMESTAMP(), :oname)
""", {
"sid": step_id,
"sname": step_name,
"kname": option_key_name,
"oname": option_name
})
db.commit()
return {"ok": True}
@router.get("/capacities/{machine_id}")
def capacities(machine_id: int, db: Session = Depends(get_db)):
return db.execute(
"SELECT capacity FROM machine_base_price WHERE machine_id=:id",
{"id": machine_id}
).fetchall()
@router.get("/factors", response_class=HTMLResponse)
def factors(request: Request, db: Session = Depends(get_db)):
rows = db.execute(text("""
SELECT ro.option_name, pf.option_id, pf.factor, pf.absolute_deduct
FROM price_option_factor pf
LEFT JOIN release_option ro ON pf.option_id = ro.option_id
""")).fetchall()
options = db.execute(text("""
SELECT DISTINCT option_id, option_name FROM release_option
""")).fetchall()
return request.app.templates.TemplateResponse(
"factors.html",
{
"request": request,
"rows": rows,
"options": options
}
)
@router.post("/factors/save")
def save_factor(
option_id: int = Form(...),
factor: float = Form(1.0),
absolute_deduct: float = Form(0),
db: Session = Depends(get_db)
):
db.execute(text("""
INSERT INTO price_option_factor(option_id,factor,absolute_deduct)
VALUES (:oid,:f,:d)
ON DUPLICATE KEY UPDATE
factor=:f, absolute_deduct=:d
"""), {
"oid": option_id,
"f": factor,
"d": absolute_deduct
})
db.commit()
return RedirectResponse("/admin/factors", status_code=302)
@router.get("/adjust", response_class=HTMLResponse)
def adjust_page(request: Request, db: Session = Depends(get_db)):
rows = db.execute(text("SELECT * FROM price_adjust_factor")).fetchall()
return request.app.templates.TemplateResponse(
"adjust.html",
{"request": request, "rows": rows}
)
@router.post("/adjust/save")
def save_adjust(
level: str = Form(...),
ref_id: int = Form(0),
factor: float = Form(...),
db: Session = Depends(get_db)
):
db.execute(text("""
INSERT INTO price_adjust_factor(level,ref_id,factor)
VALUES (:l,:r,:f)
"""), {
"l": level,
"r": ref_id,
"f": factor
})
db.commit()
return RedirectResponse("/admin/adjust", status_code=302)
@router.post("/machine-template/generate")
def generate_machine_template(
machine_id: int = Form(...),
db: Session = Depends(get_db)
):
# 1. release_option
options = db.execute(text("""
SELECT step_name, option_key_name, option_id, option_name
FROM release_option
ORDER BY step_id, option_key_id, option_id
""")).fetchall()
if not options:
return {"error": "release_option 为空"}
template = build_estimate_template(options)
# 2. 写入 machine_temp
db.execute(text("""
INSERT INTO machine_temp
(machine_id, temp_type, estimate_packet, create_time, update_time)
VALUES (:mid, '00', :json, :now, :now)
ON DUPLICATE KEY UPDATE
estimate_packet = :json,
update_time = :now
"""), {
"mid": machine_id,
"json": json.dumps(template, ensure_ascii=False),
"now": datetime.now()
})
db.commit()
return RedirectResponse("/admin/machine-templates", status_code=302)
@router.get("/machine-templates", response_class=HTMLResponse)
def machine_templates(db: Session = Depends(get_db)):
rows = db.execute(text("""
SELECT m.machine_id, m.name, m.brand_name,
mt.id AS temp_id
FROM t_machine m
LEFT JOIN machine_temp mt
ON m.machine_id = mt.machine_id
AND mt.temp_type = '00'
ORDER BY m.brand_name, m.name
LIMIT 100
""")).fetchall()
html = "机型模板管理
"
html += "| 品牌 | 机型 | 模板 | 操作 |
"
for r in rows:
status = "已生成" if r.temp_id else "未生成"
btn = "重新生成" if r.temp_id else "生成"
html += f"""
| {r.brand_name} |
{r.name} |
{status} |
|
"""
html += "
"
return html
@router.get("/categories", response_class=HTMLResponse)
def category_page(db: Session = Depends(get_db)):
rows = db.execute(text("SELECT * FROM t_chx_category")).fetchall()
html = "分类管理
"
for r in rows:
html += f"- {r.name}
"
html += "
"
html += """
新增分类
"""
return html
@router.post("/categories")
def add_category(name: str = Form(...), db: Session = Depends(get_db)):
db.execute(
text("INSERT INTO t_chx_category(category_id,name) VALUES (UNIX_TIMESTAMP(),:n)"),
{"n": name}
)
db.commit()
return RedirectResponse("/admin/categories", 302)