docs(README): 补充 isNew* 位串 0/1/2 的含义

依据 VOExtensions.cs:309-364 的 BuildListData():
  0 = 存量更新(旧数据里已有同主键条目)-> UPDATE
  1 = 新增(旧数据里没有)            -> INSERT
  2 = 无变化(只有 userFavoriteList 用)

并写明:对已存在的条目填 1 会导致 HTTP 500(服务端 INSERT 重复记录)。
This commit is contained in:
2026-10-07 23:27:30 +08:00
parent bc145fe853
commit c537e00865
2 changed files with 22 additions and 0 deletions
+21
View File
@@ -187,6 +187,27 @@ python upsert.py "<二维码>" --send --extra-data extra.json
> ⚠️ 在 PowerShell / CMD 里写内联 JSON 很容易被吞掉双引号,**建议一律用文件**。 > ⚠️ 在 PowerShell / CMD 里写内联 JSON 很容易被吞掉双引号,**建议一律用文件**。
### ★ `isNew*` 位串:0 / 1 / 2 的含义
每个数组节点都配一条 `isNew*` 位串,**一位对应数组里的一条**(顺序必须一致)。
依据 `source/Assembly-CSharp/Net.VO.Mai2/VOExtensions.cs:309-364` 的 `BuildListData()`:
| 位 | 含义 | 服务端行为 |
|---|---|---|
| `0` | **存量更新** —— 旧数据里**已有**同主键的条目 | UPDATE |
| `1` | **新增** —— 旧数据里**没有**同主键的条目 | INSERT |
| `2` | **无变化** —— 只有 `userFavoriteList` 用,其他节点不会出现 | 跳过 |
主键见 `api/upsert_user_all.py` 的 `DIFF_PRIMARY_KEYS`
(如 `userKaleidxScopeList` 用 `gateId`、`userMusicDetailList` 用 `musicId`+`level`)。
> ⚠️ **对已存在的条目填 `1` 会 HTTP 500** —— 服务端会去 INSERT 一条重复记录。
> 真机抓包样本里 `isNewFavoriteList = "22212"`,可以直观看到 0/1/2 混用的样子。
> **不确定填什么?** 先看 `data/<你的userId>.json` 里对应的节点:
> 主键已存在 → `0`,不存在 → `1`。
--- ---
## buy_ticket.py —— 购买功能票 ## buy_ticket.py —— 购买功能票
+1
View File
@@ -0,0 +1 @@
{"userKaleidxScopeList": [{"gateId": 1, "isGateFound": true, "isKeyFound": true, "isClear": false,"totalRestLife": 0, "totalAchievement": 0, "totalDeluxscore": 0,"bestAchievement": 0, "bestDeluxscore": 0,"bestAchievementDate": "", "bestDeluxscoreDate": "","playCount": 0, "clearDate": "", "lastPlayDate": "", "isInfoWatched": false},{"gateId": 3, "isGateFound": true, "isKeyFound": true, "isClear": false,"totalRestLife": 0, "totalAchievement": 0, "totalDeluxscore": 0,"bestAchievement": 0, "bestDeluxscore": 0,"bestAchievementDate": "", "bestDeluxscoreDate": "","playCount": 0, "clearDate": "", "lastPlayDate": "", "isInfoWatched": false},{"gateId": 4, "isGateFound": true, "isKeyFound": true, "isClear": false,"totalRestLife": 0, "totalAchievement": 0, "totalDeluxscore": 0,"bestAchievement": 0, "bestDeluxscore": 0,"bestAchievementDate": "", "bestDeluxscoreDate": "","playCount": 0, "clearDate": "", "lastPlayDate": "", "isInfoWatched": false},{"gateId": 5, "isGateFound": true, "isKeyFound": true, "isClear": false,"totalRestLife": 0, "totalAchievement": 0, "totalDeluxscore": 0,"bestAchievement": 0, "bestDeluxscore": 0,"bestAchievementDate": "", "bestDeluxscoreDate": "","playCount": 0, "clearDate": "", "lastPlayDate": "", "isInfoWatched": false},{"gateId": 6, "isGateFound": true, "isKeyFound": true, "isClear": false,"totalRestLife": 0, "totalAchievement": 0, "totalDeluxscore": 0,"bestAchievement": 0, "bestDeluxscore": 0,"bestAchievementDate": "", "bestDeluxscoreDate": "","playCount": 0, "clearDate": "", "lastPlayDate": "", "isInfoWatched": false}],"isNewKaleidxScopeList": "11111"}