# 企微群推送模板

## 审核通知（发布草稿后发送）

```markdown
## 🔔 新文章待审核
> 栏目：{channel_path}（ID:{channel_id}）
> 状态：<font color="warning">草稿·待审核</font>

**{文章标题}**

{一句话摘要，30字以内。来源 + 核心价值}

📝 [后台编辑审核](https://gdcjgk.net/rCIwxpQnNh.php/cms/archives/edit/ids/{article_id})

---
<font color="info">审核后在后台改状态为「发布」</font>
```

## 关键约束

- 企微 markdown 限制 **4096 bytes**（约 1300 中文字，每中文字 3 bytes）
- 超过限制报 `errcode:40058`
- 推送前用 `len(msg.encode('utf-8'))` 校验，超过则截断
- 链接必须是完整 URL，不能省略协议

## 长消息拆分策略

当输出超过 4096 bytes 时，**主动拆成多条推送**，不要等到被截断：

### 拆分规则

1. **按段落边界拆分**，不在句子中间切断
2. **每条 ≤ 3800 bytes**（留 296 bytes 安全余量给页脚/序号标注）
3. **每条末尾标注序号**：`(1/3)` `(2/3)` `(3/3)`
4. **拆分时保持语义完整**：一个 h2 段落尽量不跨消息

### 校验代码

```python
def check_and_split(content: str, max_bytes: int = 3800) -> list[str]:
    """检查字节数，超限时按段落拆分"""
    if len(content.encode('utf-8')) <= max_bytes:
        return [content]
    
    paragraphs = content.split('\n\n')
    chunks = []
    current = ''
    
    for p in paragraphs:
        test = current + ('\n\n' if current else '') + p
        if len(test.encode('utf-8')) <= max_bytes:
            current = test
        else:
            if current:
                chunks.append(current)
            current = p
    
    if current:
        chunks.append(current)
    
    # 添加序号
    total = len(chunks)
    return [f"{c}\n\n({i+1}/{total})" for i, c in enumerate(chunks)]
```

### 使用时机

| 场景 | 策略 |
|------|------|
| 小红书文案（≤1000字） | 一般不超，单条发送 |
| 选题日报（3-5个选题） | 拆2-3条，每条2个选题 |
| 官网文章全文 | 不适合企微推送全文——推摘要+后台链接 |
| 热点预警 | 单条，超过时精简措辞而非拆分 |
| 选题展开/内容框架回复 | **主动预检**，超3800 bytes就拆，末尾标序号 |
