| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- """OA 表单设计器:部门选择控件 form_data 校验"""
- from __future__ import annotations
- from typing import Any, Dict, List, Optional, Set
- def _walk_rules(rules: Any, out: List[dict]) -> None:
- if not isinstance(rules, list):
- return
- for r in rules:
- if not isinstance(r, dict):
- continue
- out.append(r)
- children = r.get("children") or (r.get("props") or {}).get("rule") or []
- if isinstance(children, list):
- _walk_rules(children, out)
- def _schema_rules(schema: Any) -> List[dict]:
- if isinstance(schema, list):
- out: List[dict] = []
- _walk_rules(schema, out)
- return out
- if not isinstance(schema, dict):
- return []
- out: List[dict] = []
- _walk_rules(schema.get("rule") or schema.get("rules") or [], out)
- return out
- def _rule_props(rule: dict) -> dict:
- props = rule.get("props")
- return props if isinstance(props, dict) else {}
- def _field_label(rule: dict) -> str:
- return str(rule.get("title") or rule.get("label") or rule.get("field") or "部门")
- def _is_required(rule: dict) -> bool:
- props = _rule_props(rule)
- if rule.get("$required") is True:
- return True
- if rule.get("required") is True:
- return True
- if props.get("required") is True:
- return True
- return False
- def _is_multiple(rule: dict) -> bool:
- props = _rule_props(rule)
- multiple = props.get("multiple")
- if multiple is None:
- return True
- return multiple is True
- def _max_count(rule: dict) -> Optional[int]:
- raw = _rule_props(rule).get("max")
- if raw is None or raw == "":
- return None
- try:
- value = int(raw)
- except (TypeError, ValueError):
- return None
- if value <= 0:
- return None
- return value
- def _is_valid_dept_item(item: Any) -> bool:
- if not isinstance(item, dict):
- return False
- dept_id = item.get("id")
- name = item.get("name")
- if not isinstance(dept_id, str) or not dept_id.strip():
- return False
- if not isinstance(name, str) or not name.strip():
- return False
- return True
- def _validate_dept_rule(rule: dict, data: Dict[str, Any]) -> List[str]:
- field = str(rule.get("field") or "").strip()
- if not field:
- return []
- label = _field_label(rule)
- required = _is_required(rule)
- multiple = _is_multiple(rule)
- max_count = _max_count(rule)
- value = data.get(field)
- errors: List[str] = []
- if multiple:
- if value is None:
- if required:
- errors.append(f"「{label}」为必填部门字段")
- return errors
- if not isinstance(value, list):
- errors.append(f"「{label}」部门字段格式不正确,应为部门列表")
- return errors
- if required and len(value) == 0:
- errors.append(f"「{label}」为必填部门字段")
- return errors
- for item in value:
- if not _is_valid_dept_item(item):
- errors.append(f"「{label}」部门项格式不正确,需包含有效的 id 与 name")
- break
- if max_count is not None and len(value) > max_count:
- errors.append(f"「{label}」选择部门数量超过最大上限 {max_count} 个")
- return errors
- if value is None or value == "":
- if required:
- errors.append(f"「{label}」为必填部门字段")
- return errors
- if isinstance(value, list):
- errors.append(f"「{label}」部门字段格式不正确,应为单个部门对象")
- return errors
- if not _is_valid_dept_item(value):
- errors.append(f"「{label}」部门字段格式不正确,需包含有效的 id 与 name")
- return errors
- def validate_dept_form_values(schema: Any, form_data: Optional[Dict[str, Any]]) -> List[str]:
- """校验 form_data 中部门 / 归属部门控件的值格式,返回中文错误列表(空表示通过)。"""
- data = form_data or {}
- errors: List[str] = []
- for rule in _schema_rules(schema):
- typ = str(rule.get("type") or "")
- if typ == "dept":
- errors.extend(_validate_dept_rule(rule, data))
- elif typ == "ownerDept":
- forced = dict(rule)
- props = dict(_rule_props(rule))
- props["multiple"] = False
- forced["props"] = props
- errors.extend(_validate_dept_rule(forced, data))
- return errors
- def extract_dept_ids(raw: Any) -> Set[str]:
- ids: Set[str] = set()
- items = raw if isinstance(raw, list) else ([raw] if isinstance(raw, dict) else [])
- for item in items:
- if not isinstance(item, dict):
- continue
- did = str(item.get("id") or "").strip()
- if did:
- ids.add(did)
- return ids
- def dept_contains_match(form_value: Any, cond_ids: Any) -> bool:
- form_ids = extract_dept_ids(form_value)
- if isinstance(cond_ids, str):
- want = {cond_ids.strip()} if cond_ids.strip() else set()
- elif isinstance(cond_ids, list):
- want = {str(x).strip() for x in cond_ids if str(x).strip()}
- else:
- want = set()
- return bool(form_ids & want)
|