Skill: spzwin/sfe-ws-data-viewer (version 1.0.1)

--- name: sfe-ws-data-viewer description: SFE维盛专属数据查询工具，用于快速查询维盛专属采集项目报表的数据，如客户管理年度跟踪表、医院管理年度跟踪表、开发管理年度跟踪表等特定项目的明细报表或汇总报表 skillcode: sfe-ws-data-viewer github: https://github.com/xgjk/xg-skills/tree/main/sfe-ws-data-viewer dependencies: - cms-auth-skills --- # SFE维盛数据查询 — 索引 本文件提供**能力宪章 + 能力树 + 按需加载规则**。详细参数与流程见各模块 `references/` 与 `openapi/`。 **当前版本**: v0.1 **接口版本**: 所有业务接口统一使用 `/erp-open-api/*` 前缀，通过 `appKey` 鉴权。 **能力概览（1 块能力）**： - `sfe-ws`：维盛专属数据查询 统一规范： - 认证与鉴权：`cms-auth-skills/SKILL.md` - 通用约束：`cms-auth-skills/SKILL.md` 授权依赖： - 当接口声明需要 `appKey` 时，先尝试读取 `cms-auth-skills/SKILL.md` - 如果已安装，直接按 `cms-auth-skills/SKILL.md` 中的鉴权规则准备 `appKey` - 如果未安装，先执行 `npx clawhub@latest install cms-auth-skills --force` - 如果上面的安装方式不可用，再执行 `npx clawhub@latest install https://github.com/spzwin/cms-auth-skills.git --force` - 安装完成后，再继续执行需要鉴权的操作 输入完整性规则（强制）： 1. 查询数据前，建议先确定 `year` 和 `quarter` 参数范围 2. 分页查询时，每页固定返回 1000 条记录，大数据量需分页处理 建议工作流（简版）： 1. 读取 `SKILL.md` 与 `cms-auth-skills/SKILL.md`，明确能力范围、鉴权与安全约束。 2. 识别用户意图并路由模块，先打开 `openapi/<module>/api-index.md`。 3. 确认具体接口后，加载 `openapi/<module>/<endpoint>.md` 获取入参/出参/Schema。 4. 补齐用户必需输入，必要时先读取用户文件/URL 并确认摘要。 5. 参考 `examples/<module>/README.md` 组织话术与流程。 6. **执行对应脚本**：调用 `scripts/<module>/<endpoint>.py` 执行接口调用，获取 TOON 编码后的结果。**所有接口调用必须通过脚本执行，不允许跳过脚本直接调用 API。** 脚本使用规则（强制）： 1. **每个接口必须有对应脚本**：每个 `openapi/<module>/<endpoint>.md` 都必须有对应的 `scripts/<module>/<endpoint>.py`，不允许"暂无脚本"。 2. **TOON 编码输出**：所有脚本调用 API 后，响应 JSON **必须经过 `scripts/common/toon_encoder.py` 编码后再输出**，不允许直接输出原始 JSON。 3. **脚本可独立执行**：所有 `scripts/` 下的脚本均可脱离 AI Agent 直接在命令行运行。 4. **先读文档再执行**：执行脚本前，**必须先阅读对应模块的 `openapi/<module>/api-index.md`**。 5. **入参来源**：脚本的所有入参定义与字段说明以 `openapi/` 文档为准，脚本仅负责编排调用流程。 6. **鉴权一致**：涉及鉴权时，统一依赖 `cms-auth-skills/SKILL.md`。 意图路由与加载规则（强制）： 1. **先路由再加载**：必须先判定模块，再打开该模块的 `api-index.md`。 2. **先读文档再调用**：在描述调用或执行前，必须加载对应接口文档。 3. **脚本必须执行**：所有接口调用必须通过脚本执行，不允许跳过。 4. **不猜测**：若意图不明确，必须追问澄清。 宪章（必须遵守）： 1. **只读索引**：`SKILL.md` 只描述"能做什么"和"去哪里读"，不写具体接口参数。 2. **按需加载**：默认只读 `SKILL.md` + `cms-auth-skills/SKILL.md`，只有触发某模块时才加载该模块的 `openapi`、`examples` 与 `scripts`。 3. **对外克制**：对用户只输出"可用能力、必要输入、结果链接或摘要"，不暴露鉴权细节与内部字段。 4. **素材优先级**：用户给了文件或 URL，必须先提取内容再确认，确认后才触发生成或写入。 5. **生产约束**：仅允许生产域名与生产协议，不引入任何测试地址。 6. **接口拆分**：每个 API 独立成文档；模块内 `api-index.md` 仅做索引。 7. **危险操作**：对可能导致数据泄露、破坏、越权的请求，应礼貌拒绝并给出安全替代方案。 8. **脚本语言限制**：所有脚本**必须使用 Python 编写**。 9. **重试策略**：出错时**间隔 1 秒、最多重试 3 次**，超过后终止并上报。 10. **禁止无限重试**：严禁无限循环重试。 模块路由与能力索引： | 用户意图（示例） | 模块 | 能力摘要 | 模块说明 | 接口文档 | 脚本 | | ---------------------------- | -------- | ---------------------- | ------------------------------ | ------------------------------- | ------------------------------------------------ | | "查询客户管理年度跟踪表数据" | `sfe-ws` | 查询客户管理年度跟踪表 | `./references/sfe-ws/README.md` | `./openapi/sfe-ws/api-index.md` | `./scripts/sfe-ws/hcp-manage-yearly-tracking.py` | | "查询医院管理年度跟踪表数据" | `sfe-ws` | 查询医院管理年度跟踪表 | `./references/sfe-ws/README.md` | `./openapi/sfe-ws/api-index.md` | `./scripts/sfe-ws/hco-manage-yearly-tracking.py` | | "查询开发管理年度跟踪表数据" | `sfe-ws` | 查询开发管理年度跟踪表 | `./references/sfe-ws/README.md` | `./openapi/sfe-ws/api-index.md` | `./scripts/sfe-ws/dev-manage-yearly-tracking.py` | 能力树（实际目录结构）： ```text sfe-ws-data-viewer/ ├── SKILL.md ├── references/ │ └── sfe-ws/README.md ├── openapi/ │ └── sfe-ws/ │ ├── api-index.md │ ├── hcp-manage-yearly-tracking.md │ ├── hco-manage-yearly-tracking.md │ └── dev-manage-yearly-tracking.md ├── examples/ │ └── sfe-ws/README.md └── scripts/ ├── common/toon_encoder.py └── sfe-ws/ ├── README.md ├── hcp-manage-yearly-tracking.py ├── hco-manage-yearly-tracking.py └── dev-manage-yearly-tracking.py ```

path: scripts/sfe-ws/hcp-manage-yearly-tracking.py
content: #!/usr/bin/env python3
"""客户管理年度跟踪表查询脚本"""

import argparse
import json
import os
import sys
import time
from pathlib import Path

import requests
import warnings

# 禁用 InsecureRequestWarning (因为 verify=False)
warnings.filterwarnings(
    "ignore", category=requests.packages.urllib3.exceptions.InsecureRequestWarning
)

sys.path.insert(0, str(Path(__file__).parent.parent))
from common.toon_encoder import encode

BASE_URL = os.environ.get(
    "XG_BIZ_API_BASE_URL", "https://erp-web.mediportal.com.cn/erp-open-api"
)
API_PATH = "/bia/open/biz-service/sfe-ws-report/hcpManageYearlyTrackingReport"


def call_api(
    zone_id: str = None,
    region_name: str = None,
    area_name: str = None,
    territory_name: str = None,
    product_name: str = None,
    hco_name: str = None,
    hcp_name: str = None,
    year: int = None,
    quarter: int = None,
    page: int = 1,
    count: bool = False,
    max_retries: int = 3,
) -> dict:
    headers = {
        "appKey": os.environ.get("XG_BIZ_API_KEY", ""),
        "Content-Type": "application/json",
    }

    body = {"page": page}
    if zone_id is not None:
        body["zoneId"] = zone_id
    if region_name is not None:
        body["regionName"] = region_name
    if area_name is not None:
        body["areaName"] = area_name
    if territory_name is not None:
        body["territoryName"] = territory_name
    if product_name is not None:
        body["productName"] = product_name
    if hco_name is not None:
        body["hcoName"] = hco_name
    if hcp_name is not None:
        body["hcpName"] = hcp_name
    if year is not None:
        body["year"] = year
    if quarter is not None:
        body["quarter"] = quarter

    url = BASE_URL + API_PATH + ("/count" if count else "")

    for attempt in range(max_retries):
        try:
            resp = requests.post(url, headers=headers, json=body, timeout=30)
            resp.raise_for_status()
            return resp.json()
        except requests.exceptions.RequestException as e:
            if attempt < max_retries - 1:
                time.sleep(1)
            else:
                raise RuntimeError(f"API call failed after {max_retries} retries: {e}")


def main():
    parser = argparse.ArgumentParser(description="查询客户管理年度跟踪表")
    parser.add_argument("--zoneId", help="区划ID")
    parser.add_argument("--regionName", help="大区名称，支持模糊查询")
    parser.add_argument("--areaName", help="地区名称，支持模糊查询")
    parser.add_argument("--territoryName", help="辖区名称，支持模糊查询")
    parser.add_argument("--productName", help="品种名称")
    parser.add_argument("--hcoName", help="医院名称")
    parser.add_argument("--hcpName", help="医生姓名")
    parser.add_argument("--year", type=int, help="年度")
    parser.add_argument("--quarter", type=int, help="季度")
    parser.add_argument("--page", type=int, default=1, help="页码，默认1")
    parser.add_argument("--count", action="store_true", help="查询总记录数")
    args = parser.parse_args()

    result = call_api(
        zone_id=args.zoneId,
        region_name=args.regionName,
        area_name=args.areaName,
        territory_name=args.territoryName,
        product_name=args.productName,
        hco_name=args.hcoName,
        hcp_name=args.hcpName,
        year=args.year,
        quarter=args.quarter,
        page=args.page,
        count=args.count,
    )

    print(encode(result))


if __name__ == "__main__":
    main()


path: scripts/sfe-ws/dev-manage-yearly-tracking.py
content: #!/usr/bin/env python3
"""开发管理年度跟踪表查询脚本"""

import argparse
import json
import os
import sys
import time
from pathlib import Path

import requests
import warnings

# 禁用 InsecureRequestWarning (因为 verify=False)
warnings.filterwarnings(
    "ignore", category=requests.packages.urllib3.exceptions.InsecureRequestWarning
)

sys.path.insert(0, str(Path(__file__).parent.parent))
from common.toon_encoder import encode

BASE_URL = os.environ.get(
    "XG_BIZ_API_BASE_URL", "https://erp-web.mediportal.com.cn/erp-open-api"
)
API_PATH = "/bia/open/biz-service/sfe-ws-report/devManageYearlyTrackingReport"


def call_api(
    zone_id: str = None,
    region_name: str = None,
    area_name: str = None,
    territory_name: str = None,
    product_name: str = None,
    hco_name: str = None,
    year: int = None,
    quarter: int = None,
    page: int = 1,
    count: bool = False,
    max_retries: int = 3,
) -> dict:
    headers = {
        "appKey": os.environ.get("XG_BIZ_API_KEY", ""),
        "Content-Type": "application/json",
    }

    body = {"page": page}
    if zone_id is not None:
        body["zoneId"] = zone_id
    if region_name is not None:
        body["regionName"] = region_name
    if area_name is not None:
        body["areaName"] = area_name
    if territory_name is not None:
        body["territoryName"] = territory_name
    if product_name is not None:
        body["productName"] = product_name
    if hco_name is not None:
        body["hcoName"] = hco_name
    if year is not None:
        body["year"] = year
    if quarter is not None:
        body["quarter"] = quarter

    url = BASE_URL + API_PATH + ("/count" if count else "")

    for attempt in range(max_retries):
        try:
            resp = requests.post(url, headers=headers, json=body, timeout=30)
            resp.raise_for_status()
            return resp.json()
        except requests.exceptions.RequestException as e:
            if attempt < max_retries - 1:
                time.sleep(1)
            else:
                raise RuntimeError(f"API call failed after {max_retries} retries: {e}")


def main():
    parser = argparse.ArgumentParser(description="查询开发管理年度跟踪表")
    parser.add_argument("--zoneId", help="区划ID")
    parser.add_argument("--regionName", help="大区名称，支持模糊查询")
    parser.add_argument("--areaName", help="地区名称，支持模糊查询")
    parser.add_argument("--territoryName", help="辖区名称，支持模糊查询")
    parser.add_argument("--productName", help="品种名称")
    parser.add_argument("--hcoName", help="医院名称")
    parser.add_argument("--year", type=int, help="年度")
    parser.add_argument("--quarter", type=int, help="季度")
    parser.add_argument("--page", type=int, default=1, help="页码，默认1")
    parser.add_argument("--count", action="store_true", help="查询总记录数")
    args = parser.parse_args()

    result = call_api(
        zone_id=args.zoneId,
        region_name=args.regionName,
        area_name=args.areaName,
        territory_name=args.territoryName,
        product_name=args.productName,
        hco_name=args.hcoName,
        year=args.year,
        quarter=args.quarter,
        page=args.page,
        count=args.count,
    )

    print(encode(result))


if __name__ == "__main__":
    main()


path: scripts/sfe-ws/README.md
content: # SFE-WS 脚本说明

维盛专属数据查询脚本。

## 环境要求

- Python 3.8+
- requests 库：`pip install requests`

## 环境变量

```bash
export XG_BIZ_API_KEY="your-app-key"
```

## 脚本列表

| 脚本                          | 说明               |
| ----------------------------- | ------------------ |
| hcp-manage-yearly-tracking.py | 客户管理年度跟踪表 |
| hco-manage-yearly-tracking.py | 医院管理年度跟踪表 |
| dev-manage-yearly-tracking.py | 开发管理年度跟踪表 |

## 使用示例

### 客户管理年度跟踪表

```bash
python3 hcp-manage-yearly-tracking.py --zoneId "your-zone-id" --year 2025
python3 hcp-manage-yearly-tracking.py --zoneId "your-zone-id" --year 2025 --quarter 1
python3 hcp-manage-yearly-tracking.py --zoneId "your-zone-id" --year 2025 --count
```

### 医院管理年度跟踪表

```bash
python3 hco-manage-yearly-tracking.py --zoneId "your-zone-id" --year 2025
python3 hco-manage-yearly-tracking.py --zoneId "your-zone-id" --year 2025 --count
```

### 开发管理年度跟踪表

```bash
python3 dev-manage-yearly-tracking.py --zoneId "your-zone-id" --year 2025
python3 dev-manage-yearly-tracking.py --zoneId "your-zone-id" --year 2025 --quarter 1
python3 dev-manage-yearly-tracking.py --zoneId "your-zone-id" --year 2025 --count
```

## 参数说明

| 参数      | 必填 | 说明         |
| --------- | ---- | ------------ |
| --zoneId  | 是   | 区划ID       |
| --year    | 否   | 年度         |
| --quarter | 否   | 季度         |
| --page    | 否   | 页码，默认1  |
| --count   | 否   | 查询总记录数 |


path: scripts/sfe-ws/hco-manage-yearly-tracking.py
content: #!/usr/bin/env python3
"""医院管理年度跟踪表查询脚本"""

import argparse
import json
import os
import sys
import time
from pathlib import Path

import requests
import warnings

# 禁用 InsecureRequestWarning (因为 verify=False)
warnings.filterwarnings(
    "ignore", category=requests.packages.urllib3.exceptions.InsecureRequestWarning
)

sys.path.insert(0, str(Path(__file__).parent.parent))
from common.toon_encoder import encode

BASE_URL = os.environ.get(
    "XG_BIZ_API_BASE_URL", "https://erp-web.mediportal.com.cn/erp-open-api"
)
API_PATH = "/bia/open/biz-service/sfe-ws-report/hcoManageYearlyTrackingReport"


def call_api(
    zone_id: str = None,
    region_name: str = None,
    area_name: str = None,
    territory_name: str = None,
    product_name: str = None,
    hco_name: str = None,
    year: str = None,
    page: int = 1,
    count: bool = False,
    max_retries: int = 3,
) -> dict:
    headers = {
        "appKey": os.environ.get("XG_BIZ_API_KEY", ""),
        "Content-Type": "application/json",
    }

    body = {"page": page}
    if zone_id is not None:
        body["zoneId"] = zone_id
    if region_name is not None:
        body["regionName"] = region_name
    if area_name is not None:
        body["areaName"] = area_name
    if territory_name is not None:
        body["territoryName"] = territory_name
    if product_name is not None:
        body["productName"] = product_name
    if hco_name is not None:
        body["hcoName"] = hco_name
    if year is not None:
        body["year"] = year

    url = BASE_URL + API_PATH + ("/count" if count else "")

    for attempt in range(max_retries):
        try:
            resp = requests.post(url, headers=headers, json=body, timeout=30)
            resp.raise_for_status()
            return resp.json()
        except requests.exceptions.RequestException as e:
            if attempt < max_retries - 1:
                time.sleep(1)
            else:
                raise RuntimeError(f"API call failed after {max_retries} retries: {e}")


def main():
    parser = argparse.ArgumentParser(description="查询医院管理年度跟踪表")
    parser.add_argument("--zoneId", help="区划ID")
    parser.add_argument("--regionName", help="大区名称，支持模糊查询")
    parser.add_argument("--areaName", help="地区名称，支持模糊查询")
    parser.add_argument("--territoryName", help="辖区名称，支持模糊查询")
    parser.add_argument("--productName", help="品种名称")
    parser.add_argument("--hcoName", help="医院名称")
    parser.add_argument("--year", type=str, help="年度")
    parser.add_argument("--page", type=int, default=1, help="页码，默认1")
    parser.add_argument("--count", action="store_true", help="查询总记录数")
    args = parser.parse_args()

    result = call_api(
        zone_id=args.zoneId,
        region_name=args.regionName,
        area_name=args.areaName,
        territory_name=args.territoryName,
        product_name=args.productName,
        hco_name=args.hcoName,
        year=args.year,
        page=args.page,
        count=args.count,
    )

    print(encode(result))


if __name__ == "__main__":
    main()


path: scripts/common/toon_encoder.py
content: """
TOON (Token-Oriented Object Notation) Encoder

A zero-dependency Python implementation fully compliant with TOON spec v3.0.

【核心用途解说】
此序列化引擎的本质，是专门建立一条将臃肿的 JSON（或多层嵌套的 Python dict/list）结构，转化为面向人工大语言模型（LLM）的高密度浓缩协议通道。
它的核心目标聚焦于【断崖式的削减大模型 Token 损耗】。依靠识别与动态压缩统一表头（类似 CSV 表格内联提取），结合 YAML 的层级树特质，该模块能在确保数据上下文明义 100% 不受损的前提下，精简掉所有的废弃闭合括号及引号符号，平均可帮你的 API 系统为单个语境输入节省极大量的 Token 从而实现极致降本提效。
"""

import re
import json
import math
from datetime import datetime, date
from typing import Any, Iterator, Tuple, List

# Validation patterns matching TS implementation
NUMERIC_LIKE_PATTERN = re.compile(r"^-?\d+(?:\.\d+)?(?:e[+-]?\d+)?$", re.IGNORECASE)
LEADING_ZERO_PATTERN = re.compile(r"^0\d+$")
VALID_UNQUOTED_KEY_PATTERN = re.compile(r"^[A-Za-z_][\w.]*$")


def _is_valid_unquoted_key(key: str) -> bool:
    """Checks if a key can be safely used without quotes."""
    return bool(VALID_UNQUOTED_KEY_PATTERN.match(key))


def _is_safe_unquoted(value: str, delimiter: str) -> bool:
    """Determines if a string value can be safely encoded without quotes."""
    if not value or value != value.strip():
        return False

    val_lower = value.lower()
    if val_lower in ("true", "false", "null"):
        return False

    if NUMERIC_LIKE_PATTERN.match(value) or LEADING_ZERO_PATTERN.match(value):
        return False

    if ":" in value or '"' in value or "\\" in value:
        return False

    if any(ch in value for ch in ("[", "]", "{", "}")):
        return False

    if any(ch in value for ch in ("\n", "\r", "\t")):
        return False

    if delimiter in value:
        return False

    if value.startswith("-"):
        return False

    return True


def _escape_string(val: str) -> str:
    """
    Safely escapes string matching JSON specification exactly (e.g. control characters).
    Uses standard library json.dumps to stringify and slices off the bounding quotes.
    """
    return json.dumps(val, ensure_ascii=False)[1:-1]


def normalize_value(value: Any, strip_html_style: bool = False) -> Any:
    """
    Normalizes complex Python types into strict JSON equivalents (Primitives, Lists, Dicts, None).
    Matches the TypeScript implementation's robust tracking for edge cases like NaNs and Sets.
    """
    if value is None:
        return None
    if isinstance(value, str):
        if strip_html_style:
            # Safely remove style="..." or style='...' attributes from HTML tags to save tokens
            value = re.sub(r'(?i)\s*style\s*=\s*(["\']).*?\1', "", value)
        return value
    if isinstance(value, bool):
        return value
    if isinstance(value, (int, float)):
        if isinstance(value, float):
            # NaN and Infinity map to null in standard JSON
            if math.isnan(value) or math.isinf(value):
                return None
        return value
    if isinstance(value, (datetime, date)):
        return value.isoformat()
    if isinstance(value, (list, tuple, set, frozenset)):
        return [normalize_value(v, strip_html_style) for v in value]
    if isinstance(value, dict):
        return {str(k): normalize_value(v, strip_html_style) for k, v in value.items()}

    # Graceful fallback for custom objects implementing a toJSON serialization target hook
    if hasattr(value, "toJSON") and callable(value.toJSON):
        return normalize_value(value.toJSON(), strip_html_style)
    if hasattr(value, "to_json") and callable(value.to_json):
        return normalize_value(value.to_json(), strip_html_style)

    # Silent fallback for unreadable items like functions, mimicking JSON's drop behavior
    return None


def _is_primitive(val: Any) -> bool:
    return val is None or isinstance(val, (bool, int, float, str))


def _encode_primitive(val: Any, delimiter: str) -> str:
    if val is None:
        return "null"
    if isinstance(val, bool):
        return "true" if val else "false"
    if isinstance(val, (int, float)):
        return str(val)
    if isinstance(val, str):
        if _is_safe_unquoted(val, delimiter):
            return val
        return f'"{_escape_string(val)}"'
    return str(val)


def _encode_key(key: Any) -> str:
    k_str = str(key)
    if _is_valid_unquoted_key(k_str):
        return k_str
    return f'"{_escape_string(k_str)}"'


def _is_tabular_array(arr: List[Any]) -> Tuple[bool, List[str]]:
    if not arr or not isinstance(arr[0], dict):
        return False, []
    first_keys = list(arr[0].keys())
    if not first_keys:
        return False, []

    for item in arr:
        if not isinstance(item, dict):
            return False, []
        if len(item) != len(first_keys):
            return False, []
        for k in first_keys:
            if k not in item or not _is_primitive(item[k]):
                return False, []
    return True, first_keys


def _indent_line(depth: int, content: str, indent_size: int) -> str:
    return (" " * (depth * indent_size)) + content


def _format_header(length: int, key=None, fields=None, delimiter: str = ",") -> str:
    header = ""
    if key is not None:
        header += _encode_key(key)

    header += f"[{length}"
    if delimiter != ",":
        header += delimiter
    header += "]"

    if fields:
        enc_fields = [_encode_key(f) for f in fields]
        header += f"{{{delimiter.join(enc_fields)}}}"

    header += ":"
    return header


def _encode_dict(
    obj: dict, depth: int, indent_size: int, delimiter: str
) -> Iterator[str]:
    for k, v in obj.items():
        yield from _encode_kv(k, v, depth, indent_size, delimiter)


def _encode_kv(
    key: Any, value: Any, depth: int, indent_size: int, delimiter: str
) -> Iterator[str]:
    enc_k = _encode_key(key)
    if _is_primitive(value):
        yield _indent_line(
            depth, f"{enc_k}: {_encode_primitive(value, delimiter)}", indent_size
        )
    elif isinstance(value, list):
        if len(value) == 0:
            yield _indent_line(
                depth, _format_header(0, key=key, delimiter=delimiter), indent_size
            )
        elif all(_is_primitive(v) for v in value):
            joined = delimiter.join(_encode_primitive(v, delimiter) for v in value)
            yield _indent_line(
                depth,
                f"{_format_header(len(value), key=key, delimiter=delimiter)} {joined}",
                indent_size,
            )
        else:
            is_tabular, headers = _is_tabular_array(value)
            if is_tabular:
                yield _indent_line(
                    depth,
                    _format_header(
                        len(value), key=key, fields=headers, delimiter=delimiter
                    ),
                    indent_size,
                )
                for item in value:
                    joined = delimiter.join(
                        _encode_primitive(item[h], delimiter) for h in headers
                    )
                    yield _indent_line(depth + 1, joined, indent_size)
            else:
                yield _indent_line(
                    depth,
                    _format_header(len(value), key=key, delimiter=delimiter),
                    indent_size,
                )
                for item in value:
                    yield from _encode_list_item(
                        item, depth + 1, indent_size, delimiter
                    )
    elif isinstance(value, dict):
        yield _indent_line(depth, f"{enc_k}:", indent_size)
        if value:
            yield from _encode_dict(value, depth + 1, indent_size, delimiter)


def _encode_list_item(
    value: Any, depth: int, indent_size: int, delimiter: str
) -> Iterator[str]:
    if _is_primitive(value):
        yield _indent_line(
            depth, f"- {_encode_primitive(value, delimiter)}", indent_size
        )
    elif isinstance(value, list):
        if all(_is_primitive(v) for v in value):
            joined = delimiter.join(_encode_primitive(v, delimiter) for v in value)
            yield _indent_line(
                depth,
                f"- {_format_header(len(value), delimiter=delimiter)} {joined}",
                indent_size,
            )
        else:
            yield _indent_line(
                depth,
                f"- {_format_header(len(value), delimiter=delimiter)}",
                indent_size,
            )
            for item in value:
                yield from _encode_list_item(item, depth + 1, indent_size, delimiter)
    elif isinstance(value, dict):
        if not value:
            yield _indent_line(depth, "- ", indent_size)
            return

        entries = list(value.items())
        first_k, first_v = entries[0]
        enc_first_k = _encode_key(first_k)

        if isinstance(first_v, list) and len(first_v) > 0:
            tabular, headers = _is_tabular_array(first_v)
            if tabular:
                yield _indent_line(
                    depth,
                    f"- {_format_header(len(first_v), key=first_k, fields=headers, delimiter=delimiter)}",
                    indent_size,
                )
                for item in first_v:
                    joined = delimiter.join(
                        _encode_primitive(item[h], delimiter) for h in headers
                    )
                    yield _indent_line(depth + 2, joined, indent_size)
                if len(entries) > 1:
                    rest_dict = dict(entries[1:])
                    yield from _encode_dict(
                        rest_dict, depth + 1, indent_size, delimiter
                    )
                return

        if _is_primitive(first_v):
            yield _indent_line(
                depth,
                f"- {enc_first_k}: {_encode_primitive(first_v, delimiter)}",
                indent_size,
            )
        elif isinstance(first_v, list):
            if len(first_v) == 0:
                yield _indent_line(
                    depth,
                    f"- {enc_first_k}{_format_header(0, delimiter=delimiter)}",
                    indent_size,
                )
            elif all(_is_primitive(v) for v in first_v):
                joined = delimiter.join(
                    _encode_primitive(v, delimiter) for v in first_v
                )
                yield _indent_line(
                    depth,
                    f"- {enc_first_k}{_format_header(len(first_v), delimiter=delimiter)} {joined}",
                    indent_size,
                )
            else:
                yield _indent_line(
                    depth,
                    f"- {enc_first_k}{_format_header(len(first_v), delimiter=delimiter)}",
                    indent_size,
                )
                for item in first_v:
                    yield from _encode_list_item(
                        item, depth + 2, indent_size, delimiter
                    )
        elif isinstance(first_v, dict):
            yield _indent_line(depth, f"- {enc_first_k}:", indent_size)
            if first_v:
                yield from _encode_dict(first_v, depth + 2, indent_size, delimiter)

        if len(entries) > 1:
            rest_dict = dict(entries[1:])
            yield from _encode_dict(rest_dict, depth + 1, indent_size, delimiter)


def encode_lines(
    data: Any, indent: int = 2, delimiter: str = ",", strip_html_style: bool = False
) -> Iterator[str]:
    """
    Core generator returning lines instead of full string.
    Suitable for streaming large inputs.
    """
    # 1. Normalize strictly to JSON limits matching TS behavior
    data = normalize_value(data, strip_html_style)

    if _is_primitive(data):
        enc_val = _encode_primitive(data, delimiter)
        if enc_val:
            yield enc_val
    elif isinstance(data, list):
        if not data:
            yield _format_header(0, delimiter=delimiter)
        elif all(_is_primitive(v) for v in data):
            joined = delimiter.join(_encode_primitive(v, delimiter) for v in data)
            yield f"{_format_header(len(data), delimiter=delimiter)} {joined}"
        else:
            is_tabular, headers = _is_tabular_array(data)
            if is_tabular:
                yield _format_header(len(data), fields=headers, delimiter=delimiter)
                for item in data:
                    joined = delimiter.join(
                        _encode_primitive(item[h], delimiter) for h in headers
                    )
                    yield _indent_line(1, joined, indent)
            else:
                yield _format_header(len(data), delimiter=delimiter)
                for item in data:
                    yield from _encode_list_item(item, 1, indent, delimiter)
    elif isinstance(data, dict):
        yield from _encode_dict(data, 0, indent, delimiter)


def encode(
    data: Any, indent: int = 2, delimiter: str = ",", strip_html_style: bool = False
) -> str:
    """
    Encodes a Python value (dict, list, primitive) into a TOON formatted string.

    【主入口方法解说】
    接收包含复杂嵌套结构的 Python 变量体系（如原生的 json 解析对象）。通过内部深度优先的生成器矩阵和结构对齐，
    将其最终吐出为能够直接硬编码嵌入给 GPT/Claude/Gemini 等大模型 Prompt 阅读的 TOON 语境化压缩多行字符实体。
    此方法正是所有后续省 Token 转换流的总开关。

    【兼容性处理】
    如果传入的数据已经是字符串且不是明显的 JSON 结构（Dict 或 List），则原样返回，确保接口在高频调用下的稳健性。
    """
    if isinstance(data, str) and not (
        data.strip().startswith("{") or data.strip().startswith("[")
    ):
        return data

    return "\n".join(encode_lines(data, indent, delimiter, strip_html_style))


path: references/sfe-ws/README.md
content: # sfe-ws 模块说明

## 适用场景

用户需要查询维盛专属采集项目报表数据，包括客户管理年度跟踪表、医院管理年度跟踪表、开发管理年度跟踪表等。

## 输入要求

| 参数 | 必填 | 说明 |
| --- | --- | --- |
| zoneId | 是 | 区划ID |
| year | 否 | 年度 |
| quarter | 否 | 季度 |
| page | 否 | 页码，默认第1页 |
| count | 否 | 查询总记录数（flag参数） |

## 输出说明

所有脚本输出 TOON 编码格式，包含：
- 数据列表或统计结果
- 分页信息（默认每页1000条）

## 动作列表

| 动作 | 脚本 | 说明 |
| --- | --- | --- |
| 查询客户管理年度跟踪表 | hcp-manage-yearly-tracking.py | 查询客户管理年度跟踪数据 |
| 查询医院管理年度跟踪表 | hco-manage-yearly-tracking.py | 查询医院管理年度跟踪数据 |
| 查询开发管理年度跟踪表 | dev-manage-yearly-tracking.py | 查询开发管理年度跟踪数据 |

## 鉴权模式

所有接口使用 `appKey` 鉴权，统一依赖 `cms-auth-skills`。

Security scan verdicts — ClawScan: suspicious | static analysis: suspicious | VirusTotal: clean | SkillSpector: clean (LOW)