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>
97 lines
3.0 KiB
Python
97 lines
3.0 KiB
Python
"""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
|