Files
zkxw/backend/app/services/oa_datetime_normalize.py
T
zlwuandCursor ac8e471aca fix: align sample registration, freight scope, and OA datetime display
Let customer-service quick register write storage, certificate, and insurance separately without extra menu or data-scope checks. List freight by document data scope like the web admin, allow protocol staff outside the collection region, and pad OA datetimes to seconds so PC date pickers can show historical minute values.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-20 17:30:30 +08:00

97 lines
3.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""OA 日期时间:PC / 小程序 valueFormat 对齐与历史到分数据兼容。
PC FormCreate(Element)在 datetime 未配置 valueFormat 时默认为
``YYYY-MM-DD HH:mm:ss``;小程序曾默认到分,导致回显空白。
本模块:对「期望到秒」的字段,将 ``YYYY-MM-DD HH:mm`` 补 ``:00``。
请假/加班等显式配置到分的字段不受影响。
"""
from __future__ import annotations
import re
from typing import Any, Dict, List, Optional
_MINUTE_ONLY_RE = re.compile(r"^(\d{4}-\d{2}-\d{2})[ T](\d{2}:\d{2})$")
def _extract_rules(form_schema: Any) -> List[Any]:
if form_schema is None:
return []
if isinstance(form_schema, list):
return form_schema
if isinstance(form_schema, dict):
rule = form_schema.get("rule")
if isinstance(rule, list):
return rule
return []
def _walk_rules(rules: List[Any], out: Optional[List[dict]] = None) -> List[dict]:
out = out if out is not None else []
for r in rules or []:
if not isinstance(r, dict):
continue
out.append(r)
children = r.get("children")
if isinstance(children, list):
_walk_rules(children, out)
props = r.get("props") or {}
nested = props.get("rule") if isinstance(props, dict) else None
if isinstance(nested, list):
_walk_rules(nested, out)
return out
def _effective_value_format(rule: dict) -> str:
props = rule.get("props") if isinstance(rule.get("props"), dict) else {}
explicit = str(props.get("valueFormat") or props.get("format") or "").strip()
if explicit:
return explicit
picker = str(props.get("type") or "date").lower()
if picker in ("datetime", "datetimerange"):
return "YYYY-MM-DD HH:mm:ss"
if picker in ("year",):
return "YYYY"
if picker in ("month", "monthrange"):
return "YYYY-MM"
return "YYYY-MM-DD"
def _expects_seconds(fmt: str) -> bool:
f = str(fmt or "")
return "ss" in f or "SS" in f
def _pad_one(val: Any) -> Any:
if not isinstance(val, str):
return val
s = val.strip()
m = _MINUTE_ONLY_RE.match(s)
if not m:
return val
return f"{m.group(1)} {m.group(2)}:00"
def _pad_value(val: Any) -> Any:
if isinstance(val, list):
return [_pad_one(x) for x in val]
return _pad_one(val)
def normalize_datetime_form_values(
form_schema: Any, form_data: Optional[Dict[str, Any]]
) -> Dict[str, Any]:
"""对期望到秒的 datePicker 字段,将到分字符串补全为到秒。返回新 dict,不改入参。"""
data = dict(form_data or {})
for rule in _walk_rules(_extract_rules(form_schema)):
typ = str(rule.get("type") or "").lower()
if typ not in ("datepicker", "fcdatepicker", "date"):
continue
field = rule.get("field")
if not field or field not in data:
continue
fmt = _effective_value_format(rule)
if not _expects_seconds(fmt):
continue
data[field] = _pad_value(data.get(field))
return data