278 lines
9.0 KiB
Python
278 lines
9.0 KiB
Python
from __future__ import annotations
|
|
|
|
from math import ceil
|
|
|
|
from app.core.db import get_db
|
|
|
|
|
|
DETECT_STATUS_LABELS = {
|
|
0: "待检测",
|
|
1: "检测完成",
|
|
2: "检测中",
|
|
3: "黑名单",
|
|
4: "检测失败",
|
|
}
|
|
|
|
REGISTER_STATUS_LABELS = {
|
|
0: "待检测",
|
|
2: "可注册",
|
|
3: "已注册",
|
|
4: "宽限期",
|
|
5: "赎回期",
|
|
6: "删除期",
|
|
7: "clientHold",
|
|
8: "serverHold",
|
|
9: "状态未知",
|
|
10: "检测失败",
|
|
}
|
|
|
|
USE_STATUS_LABELS = {
|
|
0: "未使用",
|
|
1: "已经使用",
|
|
2: "已经卖出",
|
|
3: "已经预定",
|
|
}
|
|
|
|
REVIEW_STATUS_LABELS = {
|
|
0: "无需复核",
|
|
1: "待人工复核",
|
|
2: "人工通过",
|
|
3: "人工拒绝",
|
|
}
|
|
|
|
BEIAN_STATUS_LABELS = {
|
|
1: "未检测",
|
|
2: "有备案",
|
|
3: "无备案",
|
|
}
|
|
|
|
|
|
def _build_domain_query_parts(filters: dict | None = None) -> tuple[str, str, list[object]]:
|
|
filters = filters or {}
|
|
conditions: list[str] = []
|
|
params: list[object] = []
|
|
|
|
if filters.get("domain_keyword"):
|
|
conditions.append("d.domain ilike %s")
|
|
params.append(f"%{str(filters['domain_keyword']).strip()}%")
|
|
if filters.get("register_status") is not None:
|
|
conditions.append("d.register_status = %s")
|
|
params.append(filters["register_status"])
|
|
if filters.get("detect_status") is not None:
|
|
conditions.append("d.detect_status = %s")
|
|
params.append(filters["detect_status"])
|
|
if filters.get("use_status") is not None:
|
|
conditions.append("d.use_status = %s")
|
|
params.append(filters["use_status"])
|
|
if filters.get("review_status") is not None:
|
|
conditions.append("d.review_status = %s")
|
|
params.append(filters["review_status"])
|
|
if filters.get("has_beian") is not None:
|
|
conditions.append("d.has_beian = %s")
|
|
params.append(filters["has_beian"])
|
|
if filters.get("beian_year"):
|
|
conditions.append("d.beian_year = %s")
|
|
params.append(int(filters["beian_year"]))
|
|
if filters.get("snapshot_year"):
|
|
conditions.append("coalesce(d.snapshot_years, '') like %s")
|
|
params.append(f"%{str(filters['snapshot_year']).strip()}%")
|
|
if filters.get("website_url"):
|
|
conditions.append("coalesce(d.website_url, '') ilike %s")
|
|
params.append(f"%{str(filters['website_url']).strip()}%")
|
|
if filters.get("backlink_gt_10"):
|
|
conditions.append("coalesce(dd.backlink_count_gt_10, false) = true")
|
|
|
|
from_clause = """
|
|
from domains d
|
|
left join domain_detections dd on dd.domain_id = d.id
|
|
"""
|
|
where_clause = f"where {' and '.join(conditions)}" if conditions else ""
|
|
return from_clause, where_clause, params
|
|
|
|
|
|
def fetch_domains(
|
|
page: int = 1,
|
|
page_size: int = 20,
|
|
domain_keyword: str | None = None,
|
|
register_status: int | None = None,
|
|
detect_status: int | None = None,
|
|
has_beian: int | None = None,
|
|
use_status: int | None = None,
|
|
review_status: int | None = None,
|
|
beian_year: int | None = None,
|
|
snapshot_year: str | None = None,
|
|
website_url: str | None = None,
|
|
backlink_gt_10: bool | None = None,
|
|
) -> dict:
|
|
offset = (page - 1) * page_size
|
|
filters = {
|
|
"domain_keyword": domain_keyword,
|
|
"register_status": register_status,
|
|
"detect_status": detect_status,
|
|
"has_beian": has_beian,
|
|
"use_status": use_status,
|
|
"review_status": review_status,
|
|
"beian_year": beian_year,
|
|
"snapshot_year": snapshot_year,
|
|
"website_url": website_url,
|
|
"backlink_gt_10": backlink_gt_10,
|
|
}
|
|
from_clause, where_clause, params = _build_domain_query_parts(filters)
|
|
|
|
with get_db() as conn:
|
|
with conn.cursor() as cur:
|
|
cur.execute(f"select count(*) {from_clause} {where_clause}", tuple(params))
|
|
total = cur.fetchone()[0]
|
|
cur.execute(
|
|
f"""
|
|
select
|
|
d.id,
|
|
d.domain,
|
|
d.register_status,
|
|
d.use_status,
|
|
d.detect_status,
|
|
d.review_status,
|
|
d.has_beian,
|
|
d.website_url,
|
|
d.beian_year,
|
|
d.snapshot_years,
|
|
d.backlink_count,
|
|
d.detect_time,
|
|
coalesce(dd.backlink_count_gt_10, false) as backlink_gt_10
|
|
{from_clause}
|
|
{where_clause}
|
|
order by d.id desc
|
|
limit %s offset %s
|
|
""",
|
|
tuple(params + [page_size, offset]),
|
|
)
|
|
rows = cur.fetchall()
|
|
|
|
items = [
|
|
{
|
|
"id": row[0],
|
|
"domain": row[1],
|
|
"register_status": REGISTER_STATUS_LABELS.get(row[2], str(row[2])),
|
|
"register_status_code": row[2],
|
|
"use_status": USE_STATUS_LABELS.get(row[3], str(row[3])),
|
|
"use_status_code": row[3],
|
|
"detect_status": DETECT_STATUS_LABELS.get(row[4], str(row[4])),
|
|
"detect_status_code": row[4],
|
|
"review_status": REVIEW_STATUS_LABELS.get(row[5], str(row[5])),
|
|
"review_status_code": row[5],
|
|
"has_beian": BEIAN_STATUS_LABELS.get(row[6], str(row[6])),
|
|
"has_beian_code": row[6],
|
|
"website_url": row[7] or "",
|
|
"beian_year": row[8],
|
|
"snapshot_years": row[9] or "",
|
|
"backlink_count": row[10],
|
|
"detect_time": row[11].isoformat() if row[11] else None,
|
|
"backlink_gt_10": row[12],
|
|
}
|
|
for row in rows
|
|
]
|
|
return {
|
|
"list": items,
|
|
"page": page,
|
|
"page_size": page_size,
|
|
"total": total,
|
|
"pages": ceil(total / page_size) if page_size else 1,
|
|
}
|
|
|
|
|
|
def domain_filter_options() -> dict:
|
|
return {
|
|
"register_status": [
|
|
{"label": label, "value": value}
|
|
for value, label in REGISTER_STATUS_LABELS.items()
|
|
if value in (2, 3, 4, 5, 6, 7, 8, 10)
|
|
],
|
|
"detect_status": [
|
|
{"label": label, "value": value}
|
|
for value, label in DETECT_STATUS_LABELS.items()
|
|
],
|
|
"use_status": [
|
|
{"label": label, "value": value}
|
|
for value, label in USE_STATUS_LABELS.items()
|
|
],
|
|
"review_status": [
|
|
{"label": label, "value": value}
|
|
for value, label in REVIEW_STATUS_LABELS.items()
|
|
],
|
|
"has_beian": [
|
|
{"label": "未检测", "value": 1},
|
|
{"label": "有备案", "value": 2},
|
|
{"label": "无备案", "value": 3},
|
|
],
|
|
"supports_backlink_gt_10": True,
|
|
"supports_txt_export": True,
|
|
"supports_excel_export": True,
|
|
"supports_multi_page_export": True,
|
|
}
|
|
|
|
|
|
def batch_update_domains(domain_ids: list[int], updates: dict) -> dict:
|
|
if not domain_ids:
|
|
raise ValueError("未选择需要更新的域名")
|
|
|
|
allowed_fields = {
|
|
"review_status",
|
|
"expire_date",
|
|
"has_beian",
|
|
"beian_year",
|
|
"snapshot_years",
|
|
"company_type",
|
|
"detect_time",
|
|
"website_url",
|
|
"backlink_count",
|
|
}
|
|
payload = {key: value for key, value in updates.items() if key in allowed_fields and value not in (None, "", "skip")}
|
|
if not payload:
|
|
raise ValueError("没有可更新的字段")
|
|
|
|
updated_count = 0
|
|
with get_db() as conn:
|
|
with conn.cursor() as cur:
|
|
for domain_id in domain_ids:
|
|
set_parts: list[str] = []
|
|
params: list[object] = []
|
|
|
|
for field, value in payload.items():
|
|
if field == "backlink_count":
|
|
set_parts.append("backlink_count = %s")
|
|
params.append(int(value))
|
|
else:
|
|
set_parts.append(f"{field} = %s")
|
|
params.append(value)
|
|
|
|
params.append(domain_id)
|
|
cur.execute(
|
|
f"update domains set {', '.join(set_parts)}, update_time = now() where id = %s",
|
|
tuple(params),
|
|
)
|
|
|
|
if "backlink_count" in payload:
|
|
backlink_gt_10 = int(payload["backlink_count"]) > 10
|
|
cur.execute("select id from domain_detections where domain_id = %s", (domain_id,))
|
|
if cur.fetchone():
|
|
cur.execute(
|
|
"update domain_detections set backlink_count_gt_10 = %s, update_time = now() where domain_id = %s",
|
|
(backlink_gt_10, domain_id),
|
|
)
|
|
else:
|
|
cur.execute(
|
|
"""
|
|
insert into domain_detections (domain_id, backlink_count_gt_10, create_time, update_time)
|
|
values (%s, %s, now(), now())
|
|
""",
|
|
(domain_id, backlink_gt_10),
|
|
)
|
|
|
|
updated_count += 1
|
|
conn.commit()
|
|
|
|
return {
|
|
"updated_count": updated_count,
|
|
"fields": sorted(payload.keys()),
|
|
}
|