"""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