第一版 开发完成

This commit is contained in:
Your Name
2026-01-31 23:41:19 +08:00
parent 52f540a097
commit e651b92d7c
6 changed files with 92 additions and 25 deletions
+10 -2
View File
@@ -58,7 +58,7 @@
| 项目 | 说明 |
|------|------|
| **接口** | `POST /api/projects/list` |
| **说明** | 分页获取项目列表,支持按名称/编号搜索、按进度/费用筛选、时间筛选、日期异常筛选 |
| **说明** | 分页获取项目列表,支持按名称/合同编号搜索、按进度/费用/合同金额筛选、时间筛选、日期异常筛选 |
| **权限** | 已登录,所有角色可访问 |
#### 请求参数
@@ -67,7 +67,7 @@
|--------|------|------|------|
| page | number | 否 | 页码,从 1 开始,默认 1 |
| pageSize | number | 否 | 每页条数,默认 50 |
| searchType | string | 否 | 搜索维度:`name`(项目名称)、`code`项目编号) |
| searchType | string | 否 | 搜索维度:`name`(项目名称)、`code`合同编号) |
| keyword | string | 否 | 搜索关键词,与 searchType 配合使用 |
| progress | string | 否 | 项目进度筛选,取值与业务枚举一致 |
| cost | string | 否 | 项目费用筛选,取值与业务枚举一致 |
@@ -75,6 +75,8 @@
| dateFrom | string | 否 | 时间范围起(YYYY-MM-DD),与 dateFilterType 配合 |
| dateTo | string | 否 | 时间范围止(YYYY-MM-DD),与 dateFilterType 配合 |
| dateAbnormal | boolean | 否 | 为 true 时只返回「日期异常」项目(四个日期中任意一个非「日期正常」) |
| amountMin | number | 否 | 合同金额(万元)下限,按中标合同金额筛选 |
| amountMax | number | 否 | 合同金额(万元)上限,按中标合同金额筛选 |
#### 响应参数(成功,HTTP 200
@@ -87,6 +89,12 @@
| list[].progress | string | 项目进度 |
| list[].cost | string | 项目费用 |
| list[].updatedAt | string | 最后更新时间,ISO8601 |
| list[].bidContractAmount | string | 中标合同金额(万元) |
| list[].ownerUnit | string | 业主单位 |
| list[].signDate | string | 签订日期(原文或 YYYY-MM-DD |
| list[].projectDepartment | string | 所属项目部 |
| list[].totalCost | string | 总体成本 |
| list[].projectLeaderContact | string | 项目负责人及电话 |
| total | number | 总条数,无数据时为 0 |
| page | number | 当前页码 |
| pageSize | number | 每页条数 |
+4
View File
@@ -33,6 +33,8 @@ class ProjectListBody(BaseModel):
dateFrom: Optional[str] = None
dateTo: Optional[str] = None
dateAbnormal: Optional[bool] = None # True:只查日期异常项目
amountMin: Optional[float] = None # 合同金额(万元)下限
amountMax: Optional[float] = None # 合同金额(万元)上限
class ProjectDetailBody(BaseModel):
@@ -122,6 +124,8 @@ def project_list(body: ProjectListBody, authorization: Optional[str] = Header(No
date_from=body.dateFrom,
date_to=body.dateTo,
date_abnormal=body.dateAbnormal,
amount_min=body.amountMin,
amount_max=body.amountMax,
)
return {"list": list_, "total": total, "page": page, "pageSize": page_size}
+25 -7
View File
@@ -169,8 +169,10 @@ def list_projects(
date_from: Optional[str] = None,
date_to: Optional[str] = None,
date_abnormal: Optional[bool] = None,
amount_min: Optional[float] = None,
amount_max: Optional[float] = None,
) -> tuple[list[dict], int]:
"""分页列表,支持按项目名称/合同编号搜索、按进度/费用筛选、时间筛选、日期异常筛选。返回 (list, total)。"""
"""分页列表,支持按项目名称/合同编号搜索、按进度/费用/合同金额筛选、时间筛选、日期异常筛选。返回 (list, total)。"""
with get_connection() as conn:
cur = conn.cursor(dictionary=True)
where_parts = []
@@ -191,6 +193,12 @@ def list_projects(
if cost and cost.strip():
where_parts.append("cost = %s")
params.append(cost.strip())
if amount_min is not None:
where_parts.append("(bid_contract_amount + 0) >= %s")
params.append(amount_min)
if amount_max is not None:
where_parts.append("(bid_contract_amount + 0) <= %s")
params.append(amount_max)
if date_abnormal:
where_parts.append(
"((sign_date_str IS NULL OR sign_date_str != %s) OR (start_date_str IS NULL OR start_date_str != %s) "
@@ -216,22 +224,32 @@ def list_projects(
total = cur.fetchone()["cnt"]
offset = (page - 1) * page_size
cur.execute(
f"SELECT id, project_name, contract_code, progress, cost, updated_at FROM projects WHERE {where_sql} ORDER BY updated_at DESC LIMIT %s OFFSET %s",
f"""SELECT id, project_name, contract_code, progress, cost, updated_at,
bid_contract_amount, owner_unit, sign_date, sign_date_str,
project_department, total_cost, project_leader_contact
FROM projects WHERE {where_sql} ORDER BY updated_at DESC LIMIT %s OFFSET %s""",
tuple(params) + (page_size, offset),
)
rows = cur.fetchall()
cur.close()
list_ = [
{
list_ = []
for r in rows:
_sd = r.get("sign_date")
sign_val = r.get("sign_date_str") or (_sd.strftime("%Y-%m-%d") if _sd else None)
list_.append({
"id": r["id"],
"projectName": r["project_name"] or "",
"contractCode": r["contract_code"] or "",
"progress": r["progress"] or "",
"cost": r["cost"] or "",
"updatedAt": r["updated_at"].isoformat() if r.get("updated_at") else "",
}
for r in rows
]
"bidContractAmount": r.get("bid_contract_amount") or "",
"ownerUnit": r.get("owner_unit") or "",
"signDate": sign_val or "",
"projectDepartment": r.get("project_department") or "",
"totalCost": str(r["total_cost"]) if r.get("total_cost") is not None else "",
"projectLeaderContact": r.get("project_leader_contact") or "",
})
return list_, total