逐文件精读源码生成。行号基于当前工作区版本,仅用于快速定位。
所有结构体均位于 src-tauri/src/models/ 目录下,除特别说明外,容器级 serde 属性为 #[serde(rename_all = "camelCase")](下文表格「serde」列只标注字段级 属性)。
src-tauri/src/models/mod.rs
职责 :模型模块入口,仅做子模块声明,无任何类型定义。
导出 :pub mod account(:1)、pub mod arknights(:2)、pub mod char_detail(:3)、pub mod gacha(:4)、pub mod game(:5)、pub mod login(:6)、pub mod role(:7)。
src-tauri/src/models/account.rs
职责 :账户相关数据模型——包含本地保存的完整/精简账户信息、森空岛(Skland)父级账户与用户资料的 API 反序列化结构,以及刷新/登录结果。文件共 175 行。
导出 :AccountSummary、SklandAccountInfo、SklandUserInfo、SklandGameInfo、SklandGameScore、SklandPendant、SklandBackground、SklandUserStats、AccountInfo、AccountRefreshResult、AccountLoginResult;impl AccountInfo::to_summary。
位置:account.rs:6
derive:#[derive(Serialize, Deserialize, Clone, Debug)],容器 #[serde(rename_all = "camelCase")]
用途:Account 页面使用的精简账户信息(剥离凭证等敏感字段)。
字段:
字段
类型
serde
含义
id
String
—
角色 ID(源码注释标注为 roleId)
avatar
String
—
头像地址
nickname
String
—
昵称
level
i32
—
等级
server
String
—
服务器名
status
String
—
在线状态:online/offline/loading
sync_status
Option<String>
—
同步状态:SYNCING/FAILED/null
game
String
default = "default_game"
所属游戏:endfield / arknights;老缓存缺该字段时按终末地处理
位置:account.rs:22
derive:#[derive(Serialize, Deserialize, Clone, Debug)],容器 rename_all = "camelCase"
用途:森空岛父级账户摘要,游戏角色通过 user_id 关联。
字段:
字段
类型
serde
含义
user_id
String
—
森空岛用户 ID
game_role_count
usize
—
关联的游戏角色数量
nickname
Option<String>
default + skip_serializing_if = "Option::is_none"
已缓存的森空岛昵称(来自 GET /web/v1/user,未获取过为 None)
avatar
Option<String>
default + skip_serializing_if = "Option::is_none"
已缓存的森空岛头像地址,同上
phone
Option<String>
default + skip_serializing_if = "Option::is_none"
首次登录时记录的手机号(account_token_{user_id}.phone),供「重新登录」短信/密码方式自动填充;未记录为 None
位置:account.rs:33
derive:#[derive(Serialize, Deserialize, Clone, Debug, Default)],容器 #[serde(rename_all = "camelCase", default)](缺失字段走 Default)
用途:森空岛用户资料,对应 GET /web/v1/user 响应中的 data.user。
字段:
字段
类型
serde
含义
id
String
—(容器 default)
用户 ID
nickname
String
—(容器 default)
昵称
profile
String
—(容器 default)
个人简介
avatar
String
—(容器 default)
头像地址
avatar_code
i64
—(容器 default)
头像编号
background_code
i64
—(容器 default)
背景编号
is_creator
bool
—(容器 default)
是否创作者
status
i32
—(容器 default)
账户状态码
operation_status
i32
—(容器 default)
运营状态码
identity
i32
—(容器 default)
身份标识
kind
i32
—(容器 default)
用户类型
latest_ip_location
String
—(容器 default)
最近 IP 属地
moderator_status
i32
—(容器 default)
版主状态
moderator_change_time
i64
—(容器 default)
版主状态变更时间
gender
i32
—(容器 default)
性别
birthday
String
—(容器 default)
生日
hg_id
String
—(容器 default)
鹰角账号 ID
show_id
String
—(容器 default)
展示 ID
score_info_list
Vec<SklandGameScore>
—(容器 default)
各游戏社区等级/积分
pendant
Option<SklandPendant>
skip_serializing_if = "Option::is_none"
头像挂件
stats
Option<SklandUserStats>
skip_serializing_if = "Option::is_none"
对应 data.userRts,社区互动数据(关注/粉丝/获赞等)
background
Option<SklandBackground>
skip_serializing_if = "Option::is_none"
对应 data.background,个人主页背景
位置:account.rs:68
derive:Serialize, Deserialize, Clone, Debug, Default,容器 rename_all = "camelCase", default
用途:森空岛游戏基础信息,对应 GET /web/v1/game 响应中的 data.list[].game。
字段:
字段
类型
serde
含义
game_id
i64
—(容器 default)
游戏 ID
name
String
—(容器 default)
游戏名
icon_url
String
—(容器 default)
图标地址
background_url
String
—(容器 default)
背景图地址
位置:account.rs:78
derive:Serialize, Deserialize, Clone, Debug, Default,容器 rename_all = "camelCase", default
用途:森空岛用户在单个游戏下的等级/积分。
字段:
字段
类型
serde
含义
game_id
i64
—(容器 default)
游戏 ID
level
i32
—(容器 default)
社区等级
icon_url
String
—(容器 default)
等级图标
dark_mode_icon_url
String
—(容器 default)
深色模式图标
checked_days
i32
—(容器 default)
签到天数
score
i64
—(容器 default)
积分
game_name
String
—(容器 default)
游戏名
level_url
String
—(容器 default)
等级详情链接
位置:account.rs:92
derive:Serialize, Deserialize, Clone, Debug, Default,容器 rename_all = "camelCase", default
用途:森空岛头像挂件。
字段:
字段
类型
serde
含义
id
i64
—(容器 default)
挂件 ID
icon_url
String
—(容器 default)
挂件图标
title
String
—(容器 default)
挂件标题
description
String
—(容器 default)
挂件描述
位置:account.rs:102
derive:Serialize, Deserialize, Clone, Debug, Default,容器 rename_all = "camelCase", default
用途:森空岛个人主页背景。
字段:
字段
类型
serde
含义
id
i64
—(容器 default)
背景 ID
url
String
—(容器 default)
背景图地址
resource_kind
i32
—(容器 default)
资源类型
位置:account.rs:111
derive:Serialize, Deserialize, Clone, Debug, Default,容器 rename_all = "camelCase", default
用途:森空岛社区互动数据(data.userRts),接口以字符串 返回数值,故全部字段为 String。
字段:
字段
类型
serde
含义
liked
String
—(容器 default)
获赞数(字符串)
collect
String
—(容器 default)
收藏数
comment
String
—(容器 default)
评论数
follow
String
—(容器 default)
关注数
fans
String
—(容器 default)
粉丝数
black
String
—(容器 default)
拉黑数
published
String
rename = "pub"(容器 default)
发布数,JSON 键为 pub
位置:account.rs:125
derive:Serialize, Deserialize, Clone, Debug,容器 rename_all = "camelCase"
用途:完整账户信息(含认证信息),本地持久化与命令返回的主结构。
字段:
字段
类型
serde
含义
id
String
—
角色 ID(roleId)
avatar
String
—
头像地址
nickname
String
—
昵称
level
i32
—
等级
server
String
—
服务器名
status
String
—
online/offline/loading
sync_status
Option<String>
—
SYNCING/FAILED/null
cred
Option<String>
—
认证凭证 cred
token
Option<String>
—
认证 token
user_id
Option<String>
—
森空岛 user_id
server_id
Option<String>
—
服务器 ID
game
String
default = "default_game"
所属游戏:endfield / arknights;老缓存缺该字段时按终末地处理
备注 :impl 块位于 account.rs:154。
pub fn to_summary(&self) -> AccountSummary — account.rs:156:拷贝非敏感字段转换为精简版,移除 cred/token/user_id/server_id(保留 game)。
私有 fn default_game() -> String — account.rs:148:返回 GAME_ENDFIELD,供 serde 缺省值使用。
struct AccountRefreshResult
位置:account.rs:157
derive:Serialize, Deserialize, Clone, Debug,容器 rename_all = "camelCase"
用途:账户刷新命令的返回结果。
字段:
字段
类型
serde
含义
success
bool
—
是否成功
error_message
Option<String>
—
失败原因
accounts
Vec<AccountInfo>
—
刷新后的账户列表
refresh_time
String
—
刷新时间字符串
struct AccountLoginResult
位置:account.rs:167
derive:Serialize, Deserialize, Clone, Debug,容器 rename_all = "camelCase"
用途:账户登录命令的返回结果(含可选角色列表与凭证)。
字段:
字段
类型
serde
含义
success
bool
—
是否成功
error_message
Option<String>
—
失败原因
account
Option<AccountInfo>
—
登录得到的账户
available_roles
Option<Vec<crate::models::role::RoleDisplayInfo>>
—
可选角色列表(跨模块引用 role.rs)
cred
Option<String>
—
返回的 cred
token
Option<String>
—
返回的 token
user_id
Option<String>
—
返回的 user_id
位置:account.rs:181 附近(新增)
derive:Serialize, Deserialize, Clone, Debug,容器 rename_all = "camelCase"
用途:authorize_role_u8token 命令的返回结果(按角色获取抽卡令牌)。
字段:
字段
类型
serde
含义
status
String
—
authorized / failed
message
Option<String>
—
失败原因(成功为 None)
src-tauri/src/models/char_detail.rs
职责 :角色详情(干员档案)API 响应的反序列化模型,含两个自定义反序列化器(字符串数字转换、chars 解析容错)。文件共 304 行。
导出 :CharDetailResponse、CharDetailDataWrapper、CharDetailData、BaseInfo、MainMission、CharacterItem、TalentNodes、CharacterData、RarityInfo、ProfessionInfo、PropertyInfo、WeaponTypeInfo、SkillInfo、SkillForm、SkillTypeInfo、TalentInfo、BpSystem、DailyMission、WeeklyMission。私有函数 deserialize_string_to_i64、deserialize_chars_fallback(fn,非 pub)。
struct CharDetailResponse
位置:char_detail.rs:6
derive:Serialize, Deserialize, Clone, Debug,容器 rename_all = "camelCase"
用途:角色详情接口的顶层响应包装(code/message/timestamp/data)。
字段:
字段
类型
serde
含义
code
i32
—
业务状态码
message
String
—
状态信息
timestamp
String
—
响应时间戳(字符串)
data
CharDetailDataWrapper
—
数据体
struct CharDetailDataWrapper
位置:char_detail.rs:16
derive:同上
用途:数据包装器(data.detail 一层)。
字段:
字段
类型
serde
含义
detail
CharDetailData
—
详情数据
位置:char_detail.rs:23
derive:同上
用途:角色详情主数据结构,聚合基础信息、干员列表、任务、通行证等模块。
字段:
字段
类型
serde
含义
base
BaseInfo
—
玩家基础信息
chars
Vec<CharacterItem>
default + deserialize_with = "deserialize_chars_fallback"
干员列表;解析失败时降级为空数组
dungeon
Option<serde_json::Value>
default
秘境数据(未建模,原样保留)
bp_system
Option<BpSystem>
default
战斗通行证系统
daily_mission
Option<DailyMission>
default
每日任务
weekly_mission
Option<WeeklyMission>
default
每周任务
space_ship
Option<serde_json::Value>
default
飞船数据(未建模)
domain
Option<serde_json::Value>
default
域数据(未建模)
quickaccess
Option<serde_json::Value>
default
快捷入口数据(未建模)
config
Option<serde_json::Value>
default
配置数据(未建模)
achieve
Option<serde_json::Value>
default
成就数据(未建模)
current_ts
Option<i64>
default + deserialize_with = "deserialize_string_to_i64"
当前时间戳,接受数字或字符串
备注 :自定义反序列化器:
fn deserialize_string_to_i64 — char_detail.rs:50:先把值读成 serde_json::Value,Number 直接取 i64,String 则 parse::<i64>(),其他类型报错。
fn deserialize_chars_fallback — char_detail.rs:71:Vec::<CharacterItem>::deserialize 失败时经 safe_eprintln!(有控制台才写 stderr)警告并返回空数组,避免整包解析失败。
位置:char_detail.rs:96
derive:同上
用途:基础玩家信息(角色概况、时间、计数)。
字段:
字段
类型
serde
含义
server_name
String
—
服务器名
role_id
String
—
角色 ID
name
String
—
角色昵称
create_time
String
—
创建时间(字符串)
save_time
String
—
存档时间(字符串)
last_login_time
String
—
最近登录时间(字符串)
exp
i64
—
经验值
level
i32
—
等级
world_level
i32
—
世界等级
gender
i32
—
性别
avatar_url
String
—
头像地址
main_mission
MainMission
—
主线任务
char_num
i32
—
干员数量
weapon_num
i32
—
武器数量
doc_num
i32
—
文档/档案数量
位置:char_detail.rs:117
derive:同上
用途:主线任务信息。
字段:
字段
类型
serde
含义
id
String
—
任务 ID
description
String
—
任务描述
位置:char_detail.rs:125
derive:同上;全部字段均带 #[serde(default)]
用途:干员项(API 返回格式,玩家侧养成数据)。
字段:
字段
类型
serde
含义
char_data
Option<CharacterData>
default
干员静态详情(嵌套)
id
Option<String>
default
干员 ID
level
Option<i32>
default
等级
evolve_phase
Option<i32>
default
进化/晋升阶段
potential_level
Option<i32>
default
潜能等级
user_skills
Option<serde_json::Value>
default
用户技能数据(未建模)
body_equip
Option<serde_json::Value>
default
身体装备(未建模)
arm_equip
Option<serde_json::Value>
default
臂部装备(未建模)
first_accessory
Option<serde_json::Value>
default
第一饰品(未建模)
second_accessory
Option<serde_json::Value>
default
第二饰品(未建模)
weapon
Option<serde_json::Value>
default
装备武器(未建模)
tactical_item
Option<serde_json::Value>
default
战术道具(未建模)
wiki_item_id
Option<String>
default
图鉴条目 ID
talent
Option<TalentNodes>
default
天赋节点
位置:char_detail.rs:159
derive:同上
用途:干员天赋节点信息(分能力/战斗/制造/培养四类)。
字段:
字段
类型
serde
含义
latest_break_node
String
—
最新突破节点
attr_nodes
Vec<String>
—
能力天赋节点 ID 列表
latest_passive_skill_nodes
Vec<String>
—
战斗天赋节点 ID 列表
latest_factory_skill_nodes
Vec<String>
—
制造天赋节点 ID 列表
latest_spaceship_skill_nodes
Vec<String>
—
培养(飞船)天赋节点 ID 列表
位置:char_detail.rs:170
derive:同上;全部字段均带 #[serde(default)]
用途:干员详细静态数据(稀有度、职业、技能、天赋、立绘等)。
字段:
字段
类型
serde
含义
id
Option<String>
default
干员 ID
name
Option<String>
default
干员名
avatar_sq_url
Option<String>
default
方形头像
avatar_rt_url
Option<String>
default
矩形头像
rarity
Option<RarityInfo>
default
稀有度(key/value 对)
profession
Option<ProfessionInfo>
default
职业
property
Option<PropertyInfo>
default
属性/伤害类型
weapon_type
Option<WeaponTypeInfo>
default
武器类型
skills
Option<Vec<SkillInfo>>
default
技能列表
illustration_url
Option<String>
default
立绘地址
tags
Option<Vec<String>>
default
标签
ability_talents
Option<Vec<TalentInfo>>
default
能力天赋
combat_talents
Option<Vec<TalentInfo>>
default
战斗天赋
cultivation_talents
Option<Vec<TalentInfo>>
default
培养天赋
struct RarityInfo / struct ProfessionInfo / struct PropertyInfo / struct WeaponTypeInfo / struct SkillTypeInfo
这五个结构体结构完全相同(key/value 二元组),分别位于:
RarityInfo — char_detail.rs:204(稀有度)
ProfessionInfo — char_detail.rs:212(职业)
PropertyInfo — char_detail.rs:220(属性;同时被 SkillInfo.property 复用)
WeaponTypeInfo — char_detail.rs:228(武器类型)
SkillTypeInfo — char_detail.rs:265(技能类型)
derive 均为 Serialize, Deserialize, Clone, Debug + 容器 rename_all = "camelCase"。
字段
类型
serde
含义
key
String
—
机器可读键(枚举值)
value
String
—
展示名
位置:char_detail.rs:236
derive:Serialize, Deserialize, Clone, Debug,容器 rename_all = "camelCase"
用途:干员技能信息。
字段:
字段
类型
serde
含义
id
String
—
技能 ID
name
String
—
技能名
skill_type
SkillTypeInfo
rename = "type"
技能类型(JSON 键为 type)
property
PropertyInfo
—
技能属性/伤害类型
icon_url
String
—
技能图标
desc
String
—
技能描述(含占位符)
desc_params
serde_json::Value
—
描述参数(未建模)
desc_level_params
serde_json::Value
—
各等级描述参数(未建模)
forms
Vec<SkillForm>
default
多形态技能列表
位置:char_detail.rs:253
derive:同上
用途:技能形态(如「阵诀·智/阵诀·意」等多形态技能)。
字段:
字段
类型
serde
含义
form_type
String
rename = "type"
形态类型(JSON 键为 type)
name
String
—
形态名
icon_url
String
—
形态图标
descs
Vec<String>
default
形态描述列表
位置:char_detail.rs:273
derive:同上
用途:单条天赋信息(能力/战斗/培养天赋共用)。
字段:
字段
类型
serde
含义
id
String
—
天赋 ID
name
String
—
天赋名
icon_url
String
—
天赋图标
desc
String
—
天赋描述
desc_params
Option<serde_json::Value>
—
描述参数(可为 null)
locked_icon_url
String
—
未解锁状态图标
位置:char_detail.rs:285
derive:同上
用途:战斗通行证等级。
字段:
字段
类型
serde
含义
cur_level
i32
—
当前等级
max_level
i32
—
最高等级
位置:char_detail.rs:293
derive:同上
用途:每日任务活跃度。
字段:
字段
类型
serde
含义
daily_activation
i32
—
当日活跃度
max_daily_activation
i32
—
当日活跃度上限
位置:char_detail.rs:301
derive:同上
用途:每周任务积分。
字段:
字段
类型
serde
含义
score
i32
—
当前周积分
total
i32
—
周积分上限/累计
src-tauri/src/models/gacha.rs
职责 :抽卡(寻访)数据模型——ef-webview / ak-webview 两套抽卡记录 API 的响应结构、本地持久化记录文件结构、同步结果与进度事件。
⚠️ 同一文件里装着两个游戏 的结构:终末地那组(GachaMetaData / GachaTab / GachaRecordData / GachaWeaponRecord …)与
明日方舟那组(ArknightsGachaCategory / ArknightsGachaHistoryData / ArknightsGachaRecord)。两组不能互换 ,
差异见 services/arknights_gacha_service.rs 的模块文档。
导出 :GachaApiResponse、GachaMetaData、GachaTab、GachaRecordData、GachaRecord、GachaWeaponRecordData、GachaWeaponRecord、SavedWeaponGachaData、SavedGachaData、GachaPoolInfo、GachaSyncResult、GachaSyncProgress、ArknightsGachaCategory、ArknightsGachaHistoryData、ArknightsGachaRecord ;impl GachaTab、impl GachaRecord、impl GachaWeaponRecord。依赖 std::collections::HashMap。
struct GachaApiResponse<T>
位置:gacha.rs:7
derive:Serialize, Deserialize, Clone, Debug,容器 rename_all = "camelCase"(泛型 T 需自身满足 serde bound)
用途:webview 抽卡记录 API 的统一响应包装(code = 0 表示成功)。两个游戏共用 —— 明日方舟的响应外层同样是 {status, code, msg, data}。
字段:
字段
类型
serde
含义
code
i32
—
业务状态码
msg
String
—
状态信息(注意键名是 msg,不是 message)
data
Option<T>
—
数据体,失败时为 None
struct ArknightsGachaCategory(明日方舟 )
位置:gacha.rs
derive:Serialize, Deserialize, Clone, Debug,rename_all = "camelCase"
用途:GET /api/gacha/cate 的 data[] 一项 —— 明日方舟的「卡池分类」。注意它是分类 (限定寻访·庆典 / 限定寻访·夏季 / 学生寻访 / 中坚寻访),不是终末地那种 special / joint:{poolId} / normal 的 Tab。接口还会下发 status 字段(恒为 0,与 code 重复),结构体忽略它。
字段:
字段
类型
serde
含义
id
String
—
分类 id,即 /api/gacha/history 的 category 参数(如 anniver_fest)
name
String
—
展示名,含换行符 (如 "限定寻访\n庆典"),前端展示时需替换
active
Option<bool>
default
该分类是否对应当前正在进行的卡池(仅部分分类下发)
struct ArknightsGachaHistoryData(明日方舟 )
位置:gacha.rs
用途:GET /api/gacha/history 的 data。
字段:
字段
类型
serde
含义
list
Vec<ArknightsGachaRecord>
default
本页记录(一页 10 条)
has_more
bool
—
是否还有下一页(翻页同时还要看 list 是否为空 )
struct ArknightsGachaRecord(明日方舟 )
位置:gacha.rs
用途:明日方舟单条寻访记录(接口原始形状)。⚠️ rarity 是星数减一 (5 = 六星、0 = 一星),与终末地的 rarity(直接就是星数,6 = 六星)相差 1;入库前由 ArknightsGachaService::normalize 统一 +1。
字段:
字段
类型
serde
含义
pool_id
String
—
卡池 id(如 LIMITED_79_0_1),与 cate 的分类 id 不是同一个概念
pool_name
String
—
卡池名
char_id
String
—
干员 id(如 char_4109_baslin)
char_name
String
—
干员名
rarity
i32
default
星数减一 (0..5)
is_new
bool
default
是否首次获得
gacha_ts
String
—
毫秒时间戳(字符串)。同一次十连的 10 条共用同一个值
pos
i32
default
同一次十连内的序号(0..9),用于区分与排序
struct GachaMetaData(终末地)
位置:gacha.rs:16
derive:同上
用途:GET /api/record/char/meta 的 data,卡池 Tab 列表。
字段:
字段
类型
serde
含义
tabs
Vec<GachaTab>
—
卡池 Tab 列表
beginner_pull_count
Option<i32>
default
新手寻访次数
位置:gacha.rs:25
derive:同上
用途:单个卡池 Tab 定义,决定拉取记录时的请求参数。
字段:
字段
类型
serde
含义
key
String
—
Tab 键:"special" / "joint:{poolId}" / "normal"
label
Option<String>
default
展示名
pool_type
String
—
请求记录时的 pool_type 参数
pool_id
Option<String>
default
请求记录时的 pool_id 参数(仅 joint 等有)
备注 :impl GachaTab(gacha.rs:37)
pub fn request_pool_id(&self) -> Option<&str> — gacha.rs:39:返回 pool_id.as_deref()。
位置:gacha.rs:52
derive:同上
用途:GET /api/record/char 的 data(角色寻访记录分页结果)。
字段:
字段
类型
serde
含义
list
Vec<GachaRecord>
default
本页记录
has_more
bool
—
是否还有下一页
位置:gacha.rs:61
derive:同上
用途:单条角色寻访记录。
字段:
字段
类型
serde
含义
kind
String
—
类型:draw(寻访)/ gift_intel_book(赠礼)
pool_id
String
—
卡池 ID
pool_name
String
—
卡池名
name_text
String
—
物品/角色展示名(gift 时为「寻访情报书」等)
char_id
Option<String>
default
干员 ID
char_name
Option<String>
default
干员名
rarity
Option<i32>
default
星数 (终末地原样;明日方舟由 normalize 把接口的「星数-1」+1 归一化到此字段)
is_free
Option<bool>
default
是否免费获取(仅终末地 ;明日方舟恒 None)
is_new
Option<bool>
default
是否首次获得
gacha_ts
String
—
抽卡时间,毫秒时间戳但 API 返回字符串
seq_id
String
—
全局唯一序号,同时是翻页游标。终末地:接口原样下发的 seqId(数值字符串);明日方舟:后端合成的 {poolId}|{gachaTs}|{pos} (接口没有 seqId)
pos
Option<i32>
default + skip_serializing_if
仅明日方舟 :同一次十连内的序号 0..9(同批 10 条共用 gachaTs,靠它区分与排序)。终末地恒 None
备注 :impl GachaRecord(gacha.rs:84)
pub fn is_draw(&self) -> bool — gacha.rs:85:kind == "draw"。
pub fn is_gift(&self) -> bool — gacha.rs:89:kind == "gift_intel_book"。
pub fn gacha_ts_ms(&self) -> Option<i64> — gacha.rs:94:解析 gacha_ts 为 i64,失败返回 None。
GachaRecord 是两个游戏共用的唯一记录形状 :明日方舟的记录在入库时已被
ArknightsGachaService::normalize 转成这个结构(rarity 归一为星数、seqId 合成、
kind 固定 draw、is_free 置 None、pos 带原值)。前端因此可以用同一套统计、
图表与筛选,不需要按游戏分支。
struct GachaWeaponRecordData
位置:gacha.rs:102
derive:同上
用途:GET /api/record/weapon 的 data(武器寻访记录分页结果)。
字段:
字段
类型
serde
含义
list
Vec<GachaWeaponRecord>
default
本页记录
has_more
bool
—
是否还有下一页
位置:gacha.rs:111
derive:同上
用途:单条武器寻访记录。
字段:
字段
类型
serde
含义
kind
String
—
类型,实际恒为 draw
pool_id
String
—
卡池 ID
pool_name
String
—
卡池名
name_text
String
—
武器展示名
weapon_id
Option<String>
default
武器 ID
weapon_name
Option<String>
default
武器名
weapon_type
Option<String>
default
武器类型
rarity
Option<i32>
default
稀有度
is_new
Option<bool>
default
是否首次获得
gacha_ts
String
—
抽卡时间(毫秒时间戳的字符串形式)
seq_id
String
—
全局唯一序号/翻页游标
备注 :impl GachaWeaponRecord(gacha.rs:134)
pub fn is_draw(&self) -> bool — gacha.rs:135。
pub fn gacha_ts_ms(&self) -> Option<i64> — gacha.rs:140。
struct SavedWeaponGachaData
位置:gacha.rs:148
derive:同上
用途:本地持久化的武器寻访数据,文件为 gacha_records 子目录下 gacha_weapon_records_{userId}_{serverId}.json。
字段:
字段
类型
serde
含义
user_id
String
—
账户 user_id
server_id
String
—
服务器 ID
last_sync_time
Option<i64>
default
上次同步时间(毫秒)
pools
HashMap<String, GachaPoolInfo>
default
poolId → 卡池信息
records
Vec<GachaWeaponRecord>
default
全部记录,从新到旧
位置:gacha.rs:164
derive:同上
用途:本地持久化的角色抽卡数据,文件为 app_config.json 同级目录下 gacha_records_{userId}_{serverId}.json。
字段:
字段
类型
serde
含义
user_id
String
—
账户 user_id
server_id
String
—
服务器 ID
last_sync_time
Option<i64>
default
上次同步时间(毫秒)
pools
HashMap<String, GachaPoolInfo>
default
poolId → 卡池信息
records
Vec<GachaRecord>
default
全部记录,从新到旧
位置:gacha.rs:180
derive:同上
用途:卡池基础信息(缓存于本地记录文件的 pools 映射)。
字段:
字段
类型
serde
含义
pool_name
String
—
卡池名
pool_type
String
—
卡池类型(special/joint/normal 等)
位置:gacha.rs:188
derive:同上
用途:一次增量同步的汇总结果。
字段:
字段
类型
serde
含义
user_id
String
—
账户 user_id
server_id
String
—
服务器 ID
synced_at
i64
—
同步完成时间(毫秒)
new_records
i32
—
本次新增记录数
total_records
i32
—
合并后总记录数
per_tab_new
HashMap<String, i32>
default
Tab key → 本次新增数
位置:gacha.rs:205
derive:同上
用途:增量同步进度,经 gacha-sync-progress 事件实时推送给前端。
字段:
字段
类型
serde
含义
user_id
String
—
账户 user_id
server_id
String
—
服务器 ID
tab_index
usize
—
当前 Tab 索引(从 0 开始)
tab_count
usize
—
Tab 总数
tab_key
String
—
当前 Tab 的 key(special/joint:{poolId}/normal)
page
i32
—
当前 Tab 已拉取页数
tab_fetched
usize
—
当前 Tab 本次新增记录数
total_fetched
usize
—
本次同步累计新增记录数
done
bool
—
是否已完成(最后一条进度事件为 true)
src-tauri/src/models/game.rs
职责 :游戏启动器侧模型——渠道枚举与各渠道 API/参数映射、安装/校验/修复/切服进度、启动器 API 响应结构、清单与下载相关结构、公告/Banner/背景图结构。是 models 中最大的文件(733 行),注意此文件多数结构体没有 rename_all = "camelCase" (字段本身即 snake_case,或用显式 rename/alias 处理)。
导出 :枚举 GameChannel、ActiveOperation、InstallStage;结构体 OperationProgress、SwitchProgress、GameStatus、BatchProxyResponse、ProxyResponse、GetLatestGameRsp、PkgInfo、PatchInfo、PrePatch、PatchPart、ManifestFile、RemotePackage、DownloadProgress、FilePlan、PayloadState、LauncherResult、BannerItem、AnnouncementItem、LauncherNoticeContent、BannerRsp、BannerRspItem、AnnouncementRsp、AnnouncementTab、AnnouncementApiItem、MainBgImageRsp、MainBgImageData、BackgroundMedia、FileScanResult。
位置:game.rs:13
derive:#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)](可作 HashMap key)
用途:游戏 + 服务器分支 ,并集中提供该渠道的所有 API 地址与登录参数。同一条下载/更新/预下载链路服务两个游戏,差异(appcode、CDN 一级路径、exe 名、数据目录)都收敛在这里。
变体(每个变体带显式 #[serde(rename)]):
变体
serde
含义
Official
rename = "official"
终末地 · 国服官服
Bilibili
rename = "bilibili"
终末地 · 国服 B 服
Global
rename = "global"
终末地 · 国际服
GooglePlay
rename = "google_play"
终末地 · 国际服 Google Play
Arknights
rename = "arknights"
明日方舟 · 国服官服(appcode GzD1CpaWgmSq1wew,channel/sub 1)
ArknightsBilibili
rename = "arknights_bilibili"
明日方舟 · 国服 B 服(同 appcode,channel/sub 2)
备注 :impl GameChannel(game.rs:33),全部返回 &'static str:
方法
行号
职责
as_str
game.rs:35
返回与 serde rename 一致的字符串
game_id
game.rs:49
游戏标识:endfield / arknights(Steam 图标缓存名、界面分组用)
is_arknights
game.rs:57
是否《明日方舟》(决定启动方式与数据目录)
data_dir_name
game.rs:65
数据目录名:Endfield_Data / Arknights_Data(安装完整性检测用)
api_url
game.rs:73
启动器 API:国服(含明日方舟)launcher.hypergryph.com/api/proxy/batch_proxy,国际服 launcher.gryphline.com/...
web_api_url
game.rs:83
Web API(公告/背景图),路径多一段 /web/
app_code
game.rs:93
appcode:终末地 6LL0KJuqHBVz33WK、国际服 YDUTE5gscDZ229CW、明日方舟 GzD1CpaWgmSq1wew
launcher_app_code
game.rs:102
launcher_appcode:国服(含明日方舟)abYeZZ16BPluCFyT,国际服 YDUTE5gscDZ229CW
channel
game.rs:110
官服 1 / B服 2 / 国际服与 GooglePlay 均为 6
sub_channel
game.rs:119
官服 1 / B服 2 / Global 6 / GooglePlay 802
seq
game.rs:129
国服 5(含明日方舟),国际服 3
executable_name
game.rs:137
终末地 Endfield.exe,明日方舟 Arknights.exe
process_name
game.rs:145
与 executable_name 相同(utils/process.rs 的进程快照匹配与终止用)
supports_channel_switch
game.rs:153
是否支持换服:两个游戏恒 true(实测 2026-11-08:明日方舟官/B 服差异完整落在各自清单里,约 706 MB diff,切换后 config.ini channel 随包更新)
notice_fallback_channel
game.rs:157
公告/Banner/右侧栏的回落渠道 (返回 Option<GameChannel>):B服 → 同游戏官服、GooglePlay → Global,主渠道返回 None。线上实测 B 服三项全空、官服齐全;详见 services_launcher.md 的「公告内容回落」
位置:game.rs:161
derive:#[derive(Debug, Clone, Serialize, Deserialize)],容器 #[serde(tag = "type")](内部标签枚举)
用途:当前活跃操作(统一管理安装/校验/切服状态),随 GameStatus.active_operation 返回给前端。
变体:
变体
serde
载荷类型
含义
Installing
rename = "installing"
OperationProgress
安装/下载中
Verifying
rename = "verifying"
OperationProgress
校验中
Repairing
rename = "repairing"
OperationProgress
修复中
Switching
rename = "switching"
SwitchProgress
切服中
位置:game.rs:174
derive:Debug, Clone, Serialize, Deserialize(无 rename_all ,键名即 snake_case)
用途:通用操作进度(安装/校验/修复共用)。
字段:
字段
类型
serde
含义
stage
String
—
阶段标识(对应 InstallStage::as_str 的取值)
downloaded
u64
—
已下载字节数
total
u64
—
总字节数
current_file
Option<String>
—
当前处理文件
file_index
usize
—
当前文件序号
file_count
usize
—
文件总数
verified_bytes
u64
default
已校验字节数
位置:game.rs:187
derive:同上
用途:切服进度(含阶段名与渠道信息)。
字段:
字段
类型
serde
含义
phase
String
—
切服阶段
downloaded
u64
—
已下载字节
total
u64
—
总字节
current_file
Option<String>
—
当前文件
file_index
usize
—
当前文件序号
file_count
usize
—
文件总数
from_channel
String
—
源渠道
to_channel
String
—
目标渠道
位置:game.rs:200
derive:同上
用途:游戏安装状态(前端安装页主数据)。
字段:
字段
类型
serde
含义
is_installed
bool
—
是否已安装
has_update
bool
—
是否有可用更新
local_version
Option<String>
—
本地版本
remote_version
Option<String>
—
远端最新版本
has_preload
bool
—
是否有预下载资源
preload_version
Option<String>
—
预下载版本
preload_installable
bool
default
有 cd_key 且补丁可用于安装;此时 has_update 也为 true
preload_total_bytes
u64
default
预下载分卷需下载的总字节数(无预下载时为 0)
preload_completed
bool
—
预下载是否完成
active_operation
Option<ActiveOperation>
default
当前活跃操作(无则为 None)
struct BatchProxyResponse
位置:game.rs:219
derive:同上
用途:启动器 batch_proxy 接口的顶层响应。
字段:
字段
类型
serde
含义
proxy_rsps
Vec<ProxyResponse>
—
各子请求的响应集合
位置:game.rs:224
derive:同上
用途:单个子请求响应,按 kind 分派到对应 *_rsp 字段。
字段:
字段
类型
serde
含义
kind
String
—
响应种类
get_latest_game_rsp
Option<GetLatestGameRsp>
rename(同名) + skip_serializing_if = "Option::is_none"
最新版本响应
get_banner_rsp
Option<BannerRsp>
rename(同名) + skip_serializing_if = "Option::is_none"
Banner 响应
get_announcement_rsp
Option<AnnouncementRsp>
rename(同名) + skip_serializing_if = "Option::is_none"
公告响应
get_main_bg_image_rsp
Option<MainBgImageRsp>
rename(同名) + skip_serializing_if = "Option::is_none"
主界面背景图响应
get_sidebar_rsp
Option<SidebarRsp>
rename(同名) + skip_serializing_if = "Option::is_none"
右侧栏(社媒/工具)响应
位置:game.rs:248
derive:同上
用途:最新游戏包信息(含版本补丁包 patch 与预下载补丁包 pre_patch)。
字段:
字段
类型
serde
含义
action
i32
default
0 = 无需更新,1 = 有新版本(整包)
version
String
—
最新版本号
client_version
String
default
服务端视角的客户端版本
launcher_action
i32
default
启动器维度动作(是否需要先更启动器)
pkg
Option<PkgInfo>
default
正式包信息
patch
Option<PatchInfo>
default
版本补丁包(cd_key 的真值位置 ;只有带上本地版本时才返回)
pre_patch
Option<PrePatch>
default
预下载补丁包(官方在正式发版前提供,只有请求里带上本地版本时才返回)
备注 :接口实际响应还包含 request_version / state / pkg.packs 等字段。逆向结论(Games.exe CLibNetworkUtils::ParseLatestGameJson @ 0x002f1e80 的字段解析顺序 + 线上响应实测):cd_key / v2_* / patches 都属于 patch 对象 ,pkg 里没有 cd_key;pre_patch 里也没有密钥字段,因此"安装预下载包"必须等到正式发版、patch 下发后才能进行。
位置:game.rs:278
derive:同上
用途:包地址信息(pkg.file_path 指向资源根目录,清单由 {file_path}/game_files 取得)。
字段:
字段
类型
serde
含义
file_path
String
—
包文件下载路径/URL
cd_key
Option<String>
default + skip_serializing
历史兼容位 :实测响应里 pkg 无此键,真值在 PatchInfo::cd_key;保留作为兜底读取
位置:game.rs:293
derive:Debug, Clone, Serialize, Deserialize, Default
用途:版本补丁包(get_latest_game_rsp.patch)。官方常规更新走这条通道:下载加密分卷 → 用 7zg.exe x -y -o"…" -p"<cd_key>" 解密解压 → 覆盖/删除。
字段:
字段
类型
serde
含义
cd_key
String
default
补丁包密钥:既是 WinZip AES 分卷的 zip 密码,也是 verify_files 的密钥来源
url
String
default
未加密的整补丁 zip(回退形态,可直取)
md5
String
default
整补丁 zip 的 MD5
package_size
String
default
分卷合计字节数(字符串数字)
total_size
String
default
服务端"预留空间"估计(不是 解压后大小,实测倍率 1.66×~2.5×)
file_id
String
default
包 ID
patches
Vec<PatchPart>
default
加密分卷列表(.zip.001 … 顺序拼接为一个 ZIP)
v2_patch_info_url / _md5 / _size
String
default
V2 明文补丁索引(patch.json),可为空
v2_verify_files_url / _md5 / _size
String
default
V2 加密校验清单(verify_files),可为空
v2_verify_category_list
Vec<String>
default
校验分类(如 ["move","patch"])
备注 :impl PatchInfo — game.rs:327;方法 normalized_cd_key(&self) -> Option<String>(game.rs:329,去空白、空串视为不可用)、total_bytes(&self) -> u64(game.rs:339,累加分卷 size(),无分卷时回退 package_size)与 is_delta(&self) -> bool(game.rs:355,v2_patch_info_url 非空即为差量包)。
is_delta 是"能不能直接铺"的分水岭(线上实测):终末地 1.6.3→1.6.4 的 v2_patch_info_url 为空,包内条目就是最终文件,解压即可用;明日方舟 78.0.0→79.0.0 该字段指向 patch.json,包内是 vfs_files/vfs_patch/diff_<old>_<new>/xxx.ab_patch,必须由 Patch.exe(hpatch)结合本地 base 文件生成新文件,本实现不含 hpatch,因此改走 patch.url 那份明文整补丁 zip (条目同样是最终文件)。
位置:game.rs:362
derive:Debug, Clone, Serialize, Deserialize, Default
用途:预下载补丁包元数据(待发布版本的分卷压缩包)。
字段:
字段
类型
serde
含义
version
String
default
预下载目标版本(尚未正式发布的新版本)
client_version
String
default
官方客户端上报的版本,实测与 version 相同
package_size
String
default
分卷下载总字节数(字符串数字,等于各分卷 package_size 之和)
total_size
String
default
服务端"预留空间"估计(不是 解压后大小;进度分母应以实际解压条目之和为准)
patches
Vec<PatchPart>
default
分卷列表(.zip.001、.zip.002 … 顺序拼接为一个 ZIP)
备注 :pre_patch 不含 cd_key ——官方只在正式发版后通过 patch 下发密钥,因此"预下载"只负责提前把分卷下好。impl PrePatch — game.rs:380;方法 total_bytes(&self) -> u64 — game.rs:339,累加各分卷 size()。
位置:game.rs:389
derive:Debug, Clone, Serialize, Deserialize, Default
用途:预下载分卷条目。
字段:
字段
类型
serde
含义
url
String
default
CDN 地址(带 auth_key 查询串,过期后需重新请求 API)
md5
String
default
分卷文件 MD5
package_size
String
default
分卷字节数(字符串数字)
备注 :impl PatchPart — game.rs:401;方法 size(&self) -> u64 — game.rs:403,解析 package_size,失败按 0。
位置:game.rs:410
derive:同上
用途:清单文件条目(解密后的 NDJSON 每行一条)。
字段:
字段
类型
serde
含义
path
String
—
相对路径
md5
String
—
文件 MD5
size
i64
—
文件字节数
位置:game.rs:418
derive:同上
用途:远端游戏包信息(版本 + 资源地址,含补丁包与预下载)。不含解密密钥 (cd_key 只留在后端)。
字段:
字段
类型
serde
含义
version
String
—
版本号
resource_base_url
String
—
资源下载根地址(pkg.file_path)
has_preload
bool
—
是否存在预下载
preload_version
Option<String>
—
预下载版本
preload_parts
Vec<PatchPart>
—
预下载分卷列表(顺序即拼接顺序)
preload_total_bytes
u64
—
预下载分卷下载字节数之和
preload_expanded_bytes
u64
—
pre_patch.total_size(服务端预留估计 ,只作进度兜底)
has_patch
bool
default
服务端是否下发了版本补丁包
patch_parts
Vec<PatchPart>
default
补丁分卷列表(WinZip AES 加密)
patch_total_bytes
u64
default
补丁分卷下载字节数之和
has_patch_whole
bool
default
是否有未加密整补丁包(patch.url)
patch_is_delta
bool
default
补丁包是否为差量形态(PatchInfo::is_delta;为真时不做加密分卷路径)
patch_whole_url
String
default
未加密整补丁 zip 地址(patch.url)——差量包的兜底形态,条目就是最终游戏文件
patch_whole_md5
String
default
整补丁 zip 的 MD5(patch.md5;实测就是 patch.url 那份包的 md5)
patch_whole_bytes
u64
default
patch.package_size(分卷合计 ,不是整包长度:明日方舟 79.0.0 为 1,221,839,400,而整包实际 3,518,344,483 B)。仅用于日志/预估,进度以 Content-Length 为准
位置:game.rs:457
derive:同上
用途:下载进度(与 OperationProgress 字段基本一致)。
字段:
字段
类型
serde
含义
downloaded
u64
—
已下载字节
total
u64
—
总字节
stage
String
—
阶段
current_file
Option<String>
—
当前文件
file_index
usize
—
当前文件序号
file_count
usize
—
文件总数
verified_bytes
u64
default
已校验字节
备注 :手动实现 impl Default for DownloadProgress — game.rs:468,全字段置 0/空(stage 为 String::new(),current_file 为 None)。
位置:game.rs:484
derive:Debug, Clone, Serialize, Deserialize, PartialEq, Eq
用途:安装/更新阶段枚举,序列化为小写字符串。
变体(均带 #[serde(rename)],rename 值与 as_str 一致):
变体
serde 值
含义
Checking
checking
检查
Comparing
comparing
比对清单
Downloading
downloading
下载
Verifying
verifying
校验
Repairing
repairing
修复
Preloading
preloading
预下载(官方预发布补丁分卷,仅 preload_download 使用)
Applying
applying
应用/落盘
Completed
completed
完成
Error
error
出错
备注 :impl InstallStage — game.rs:506;pub fn as_str(&self) -> &'static str — game.rs:35,返回上表字符串。
位置:game.rs:524
derive:#[derive(Debug, Clone)] —— 不带 serde,不能直接序列化
用途:清单比较结果,标记需要下载的文件及其可复用的本地来源。
字段:
字段
类型
serde
含义
manifest
ManifestFile
无(不实现 serde)
目标文件清单条目
source_path
Option<String>
无
本地已有且 MD5 匹配的文件路径(可复用)
位置:game.rs:531
derive:Debug, Clone, Serialize, Deserialize
用途:持久化的资源包状态(写入本地状态文件)。
字段:
字段
类型
serde
含义
channel
String
—
渠道字符串
version
String
—
已安装版本
manifest_sha256
String
—
清单文件 SHA256
file_count
usize
—
文件总数
total_bytes
u64
—
总字节数
updated_at
String
—
更新时间字符串
preload_version
Option<String>
default
预下载版本
preload_completed
bool
default
预下载是否完成
位置:game.rs:546
derive:同上
用途:安装/更新操作结果(命令返回值)。
字段:
字段
类型
serde
含义
success
bool
—
是否成功
message
String
—
结果描述。launcher_start_game 用 <token>: <detail> 形式(token 见 commands.md 的 token 契约表),前端据此选 i18n 文案
version
Option<String>
—
成功后的版本号
warning
Option<String>
default + skip_serializing_if
非致命提示,格式同 message。目前只有「未找到签名有效的官方启动器、已回退到直接启动」(token fallback)会带上
位置:game.rs:560
derive:同上
用途:本地聚合后的 Banner 条目(给前端)。
字段:
字段
类型
serde
含义
image_url
String
—
图片地址
jump_url
String
—
跳转链接
位置:game.rs:567
derive:同上
用途:本地聚合后的公告条目。
字段:
字段
类型
serde
含义
category
String
—
所属 Tab/分类
title
String
—
标题
date
String
—
日期字符串
jump_url
String
—
跳转链接
struct LauncherNoticeContent
位置:game.rs:576
derive:同上
用途:公告页聚合内容(Banner + 公告列表 + 右侧栏条目)。
字段:
字段
类型
serde
含义
banners
Vec<BannerItem>
—
Banner 列表
announcements
Vec<AnnouncementItem>
—
公告列表
sidebars
Vec<SidebarItem>
—
启动器右侧栏条目(社媒二维码 + 工具入口),由 get_sidebar 合并而来
struct SidebarItem
位置:game.rs:588
derive:同上
用途:后端聚合后的 侧边栏条目(给前端)。官方数据把链接分散在条目自身与 sidebar_labels[] 两处,GameLauncherService::parse_sidebars 已合并成这一层扁平结构,前端不再处理分组。
字段:
字段
类型
serde
含义
media
String
—
渠道标识(Skland/Bilibili/Weibo/Taptap/Douyin/Xiaohongshu/Wechat/CS/SklandTool),前端据此匹配本地图标
display_type
String
—
原样透传:DisplayType_LIST(单条链接)/ DisplayType_GRID(一组工具链接)
title
String
—
悬停提示与二维码说明(pic.description,缺失时取 sidebar_labels[0].content)
qr_url
String
—
二维码图片地址(pic.url,缺失时取 sidebar_labels[0].pic_url),空串表示无图
jump_url
String
—
点击打开的网页地址,空串表示只能扫码(如微信公众号)
need_token
bool
—
官方是否要求带登录态(仅透传,当前前端未使用)
struct SidebarRsp
位置:game.rs:646
derive:同上
用途:get_sidebar_rsp 响应体。
字段:
字段
类型
serde
含义
sidebars
Vec<SidebarApiItem>
default
侧边栏原始条目列表
struct SidebarApiItem
位置:game.rs:652
derive:同上
用途:侧边栏 API 原始条目(含分组结构,仅后端解析用)。
字段:
字段
类型
serde
含义
media
String
default
渠道标识
display_type
String
default
DisplayType_LIST / DisplayType_GRID
pic
Option<SidebarPic>
default
二维码图片(CS、SklandTool 为 null)
sidebar_labels
Vec<SidebarLabel>
default
子链接列表(GRID 有 6 条,CS 有 1 条)
jump_url
String
default
条目自身跳转地址(社媒条目使用)
need_token
bool
default
是否需要登录态
struct SidebarPic / struct SidebarLabel
位置:game.rs:501 / game.rs:509
derive:同上
用途:侧边栏条目的图片与子链接。SidebarPic { url, description: Option<String> };SidebarLabel { content, jump_url, pic_url, need_token }(全部 default)。
位置:game.rs:606
derive:同上
用途:Banner API 响应体。
字段:
字段
类型
serde
含义
banners
Vec<BannerRspItem>
default
Banner 列表
位置:game.rs:612
derive:同上
用途:Banner API 原始条目。
字段:
字段
类型
serde
含义
url
String
—
图片地址
jump_url
String
—
跳转链接
位置:game.rs:619
derive:同上
用途:公告 API 响应体。
字段:
字段
类型
serde
含义
tabs
Vec<AnnouncementTab>
default + alias = "tab_list"
公告 Tab 列表(兼容 tab_list 键)
位置:game.rs:625
derive:同上
用途:公告 API 中的分类 Tab。
字段:
字段
类型
serde
含义
tab_name
String
alias = "tab_name" + alias = "tabName" + default
Tab 名称
announcements
Vec<AnnouncementApiItem>
default
该 Tab 下的公告
struct AnnouncementApiItem
位置:game.rs:633
derive:同上
用途:公告 API 原始条目(字段宽松,多为 Option)。
字段:
字段
类型
serde
含义
content
String
default
公告正文
title
Option<String>
default + alias = "title"
标题
start_ts
Option<String>
default + alias = "startTs" + alias = "start_ts"
开始时间(字符串)
jump_url
Option<String>
default + alias = "jumpUrl" + alias = "jump_url"
跳转链接
位置:game.rs:689
derive:同上
用途:主界面背景图 API 响应体。
字段:
字段
类型
serde
含义
main_bg_image
Option<MainBgImageData>
rename = "main_bg_image"(同名) + default
背景图数据
位置:game.rs:695
derive:同上
用途:背景图数据(可含视频)。
字段:
字段
类型
serde
含义
url
String
—
图片地址
video_url
Option<String>
default
视频地址
位置:game.rs:703
derive:同上
用途:启动器背景媒体,图片与视频一起返回,由前端按设置选择。
字段:
字段
类型
serde
含义
image_url
Option<String>
default
背景图地址
video_url
Option<String>
default
背景视频地址
位置:game.rs:712
derive:同上
用途:安装目录扫描结果(校验本地文件完整性统计)。
字段:
字段
类型
serde
含义
channel_detected
bool
—
是否识别出渠道
detected_channel
Option<String>
—
识别到的渠道字符串
total_files
usize
—
清单中的总文件数
valid_files
usize
—
已存在且完整的文件数
corrupted_files
usize
—
已存在但损坏的文件数
missing_files
usize
—
缺失文件数
existing_bytes
u64
—
已存在文件总字节
download_bytes
u64
—
需下载的总字节
corrupted_file_list
Vec<String>
—
损坏文件路径(最多 20 条)
missing_file_list
Vec<String>
—
缺失文件路径(最多 20 条)
src-tauri/src/models/login.rs
职责 :登录相关的请求/响应模型(密码登录、验证码、扫码登录)。文件共 52 行。
导出 :LoginRequest、SendCodeRequest、CodeLoginRequest、ScanLoginInfo、ScanStatus。
位置:login.rs:6
derive:#[derive(Serialize, Deserialize, Clone, Debug)],容器 rename_all = "camelCase"
用途:密码登录请求体。
字段:
字段
类型
serde
含义
phone
String
—
手机号
password
String
—
密码
expected_user_id
Option<String>
default
重新登录时的目标森空岛 userId;登录结果不一致时后端返回 ACCOUNT_MISMATCH:<实际userId> 且不保存凭证
位置:login.rs:14
derive:同上
用途:发送验证码请求体。
字段:
字段
类型
serde
含义
phone
String
—
手机号
code_type
i32
rename = "type"
验证码类型(JSON 键为 type)
位置:login.rs:23
derive:同上
用途:验证码登录请求体。
字段:
字段
类型
serde
含义
phone
String
—
手机号
code
String
—
短信验证码
expected_user_id
Option<String>
default
重新登录时的目标森空岛 userId(校验同 LoginRequest)
位置:login.rs:31
derive:同上
用途:扫码登录信息(生成二维码所需)。
字段:
字段
类型
serde
含义
scan_id
String
—
扫码会话 ID
scan_url
String
—
二维码指向的 URL
位置:login.rs:39
derive:同上
用途:扫码登录轮询状态。
字段:
字段
类型
serde
含义
status
i32
—
100 = 未扫码,101 = 已扫码,0 = 登录成功(此时返回 scan_code)
scan_code
Option<String>
—
登录成功时的扫码凭据
msg
Option<String>
—
提示信息(JSON 键为 msg)
src-tauri/src/models/role.rs
职责 :角色/绑定相关模型——森空岛绑定列表的 API 响应结构、从绑定列表展平出来的 GameRoleBinding、本地配置用的角色展示结构。文件共 129 行。
导出 :GameBinding、BindingInfo、RoleInfo、BindingResponse、BindingData、GameRoleBinding、RoleDisplayInfo;常量 GAME_ENDFIELD、GAME_ARKNIGHTS;impl RoleDisplayInfo::is_arknights;私有 default_game。
位置:role.rs:6
derive:#[derive(Serialize, Deserialize, Clone, Debug)],容器 rename_all = "camelCase"
用途:一个游戏(app)的绑定聚合。
字段:
字段
类型
serde
含义
app_code
String
—
应用代码
app_name
String
—
应用/游戏名
binding_list
Vec<BindingInfo>
—
绑定列表
default_uid
Option<String>
—
默认 UID
位置:role.rs:16
derive:同上
用途:单个渠道绑定信息(含其下的角色列表)。
字段:
字段
类型
serde
含义
uid
String
—
账号 UID
is_official
bool
—
是否官服绑定
is_default
bool
—
是否默认绑定
channel_master_id
String
—
渠道主 ID
channel_name
String
—
渠道名
nick_name
String
—
绑定昵称
is_delete
bool
—
是否已删除
game_name
String
—
游戏名
game_id
i32
—
游戏 ID
roles
Vec<RoleInfo>
—
该渠道下的角色列表。⚠️ 终末地有值,明日方舟恒为空数组 —— 明日方舟的角色信息在 BindingInfo 这一层(uid / nick_name / channel_master_id)
default_role
Option<RoleInfo>
—
默认角色(终末地有值,明日方舟为 null)
位置:role.rs:33
derive:同上
用途:单个游戏角色信息(来自绑定列表接口)。
字段:
字段
类型
serde
含义
server_id
String
—
服务器 ID
role_id
String
—
角色 ID
nickname
String
—
角色昵称
level
i32
—
等级
is_default
bool
—
是否默认角色
is_banned
bool
—
是否被封禁
server_type
String
—
服务器类型
server_name
String
—
服务器名
位置:role.rs:47
derive:同上
用途:绑定列表接口的顶层响应(code/message/timestamp/data)。
字段:
字段
类型
serde
含义
code
i32
—
业务状态码
message
String
—
状态信息
timestamp
String
—
响应时间戳(字符串)
data
BindingData
—
数据体
位置:role.rs:56
derive:同上
用途:绑定列表响应的数据体。
字段:
字段
类型
serde
含义
list
Vec<GameBinding>
—
游戏绑定列表
server_default_binding
serde_json::Value
—
服务器默认绑定(未建模,原样保留)
位置:role.rs:72
derive:Serialize, Deserialize, Clone, Debug,容器 rename_all = "camelCase"
用途:从绑定接口展平出来的单条角色记录(不联网、只含绑定侧基础信息),由 SklandService::extract_game_roles 产出。明日方舟角色的昵称/等级/服务器全部来自这里 —— 它没有终末地的 card/detail 接口。
⚠️ 两个游戏的角色在不同层级 :终末地在 bindingList[].roles[];明日方舟的 roles 是空数组 ,角色在 bindingList 这一层 —— role_id 用 uid、server_id 用 channelMasterId、nickname 用 nickName、level 留 0(由 player/info.status.level 补)。已用真实账号验证 player/info.status.uid == 绑定 uid,故「uid 即角色标识」可靠。
字段:
字段
类型
serde
含义
game
String
—
endfield / arknights(来自 GameBinding.app_code)
binding_uid
String
—
渠道绑定 uid(官服 / B 服各一个)
channel_master_id
String
—
渠道主 ID
channel_name
String
—
渠道名
server_id
String
—
服务器 ID。终末地取 roles[].serverId;明日方舟取 channelMasterId (1=官服 2=B服,前端 resolveServerLabel 正好认这两个值)
server_name
String
—
服务器展示名。终末地取 roles[].serverName(如 China);明日方舟取 channelName(如 官服)
role_id
String
—
角色 ID。终末地取 roles[].roleId;明日方舟没有 roleId,直接用 uid
nickname
String
—
角色昵称。终末地取 roles[].nickname;明日方舟取 bindingList[].nickName(形如 Doctor#1234)
level
i32
—
等级。终末地取 roles[].level;明日方舟绑定接口不给,恒为 0 ,由 player/info.status.level 回填后落盘
位置:role.rs:90
derive:同上
用途:面向前端的角色展示信息(被 account.rs::AccountLoginResult.available_roles 复用),也后端接收 save_selected_roles 的入参。
字段:
字段
类型
serde
含义
role_id
String
—
角色 ID
user_id
String
—
账户 user_id
server_id
String
—
服务器 ID
nickname
String
—
昵称
level
i32
—
等级
avatar_url
String
—
头像地址。终末地来自 card/detail 的 base.avatarUrl;明日方舟来自 player/info 的 status.avatar.url (该接口是它唯一的头像来源)
game
String
default = "default_game"
角色所属游戏:endfield / arknights。老数据缺该字段时兜底为 endfield
binding_uid
String
default
该角色所属的渠道绑定 uid (官服 / B 服各一个),换 u8token 的必需键
channel_master_id
String
default
渠道主 ID(1 = 官服,2 = B 服),仅展示
channel_name
String
default
渠道名(绑定接口的 channelName),仅展示
u8_authorized
bool
default
该角色是否已授权抽卡数据访问。构建角色列表时由 AccountService::is_role_u8_authorized 回填 —— 漏掉这个回填会导致前端永远显示「未授权」
备注 :impl RoleDisplayInfo(role.rs:124)— pub fn is_arknights(&self) -> bool(role.rs:126):game == GAME_ARKNIGHTS。
src-tauri/src/models/arknights.rs
职责 :《明日方舟》数据模型 —— 森空岛 player/info / cultivate/player / attendance 三个接口的反序列化结构。与终末地完全分开 :终末地按 roleId + serverId 走 card/detail 一次返回一个角色,明日方舟按渠道绑定 uid 走 player/info 一次返回整个账号。文件约 470 行(含单元测试)。
导出 :ArknightsPlayerInfo、ArknightsStatus、ArknightsAp、ArknightsAvatar、ArknightsSecretary、ArknightsChar、ArknightsSkill、ArknightsEquip、ArknightsRecruitSlot、ArknightsRoutine、ArknightsCampaign、ArknightsTower、ArknightsTowerReward、ArknightsBuilding、ArknightsLabor、ArknightsHire、ArknightsTraining、ArknightsTrainee、ArknightsTrainer、ArknightsTiredChar、ArknightsRoomSegment、ArknightsRoomChar、ArknightsCultivate、ArknightsCultivateChar、ArknightsCultivateSkill、ArknightsCultivateEquip、ArknightsItem、ArknightsAttendance、ArknightsAttendanceReward、ArknightsCalendarEntry、ArknightsCheckinRecord、ArknightsAward、ArknightsAwardResource、ArknightsAttendanceResult、ArknightsProgress、ARKNIGHTS_ITEM_ICON_BASE、arknights_item_icon_url();私有 one_or_many、one_or_many_default、string_or_i64、local_day_key。
空值约定 :真实返回里 building.hire(办公室未建造)与 building.training(无进行中专精)是 null。skland-api 的 recruit.py:38 就是因为直接下标而崩。本文件所有 building.* 子对象一律 Option<T>,容器级 #[serde(default)] 保证字段缺失走 Default 而不是整包失败。
struct ArknightsPlayerInfo
位置:arknights.rs:118
derive:Serialize, Deserialize, Clone, Debug, Default,容器 rename_all = "camelCase", default
用途:GET /api/v1/game/player/info?uid= 的 data。明日方舟的唯一主数据源 (干员养成、基建、任务、剿灭、保全、公招全在里面,cultivate 只额外给仓库)。
字段:
字段
类型
serde
含义
status
ArknightsStatus
容器 default
玩家基础状态(昵称/等级/理智/头像…)
chars
Vec<ArknightsChar>
容器 default
干员养成(含精英化/等级/专精/潜能/信赖/模组/皮肤)
char_info_map
serde_json::Map<String, Value>
容器 default
干员静态表:charId → {id, name, profession, rarity, …}
recruit
Vec<ArknightsRecruitSlot>
容器 default
公开招募栏位(state == 2 为招募中)
routine
ArknightsRoutine
容器 default
每日/每周任务
campaign
ArknightsCampaign
容器 default
剿灭作战
tower
ArknightsTower
容器 default
保全派驻
building
ArknightsBuilding
容器 default
基建(hire/training 可能为 null)
current_ts
i64
容器 default
数据生成时间戳(该接口为数字)
未建模的字段(activity、bannerList、skins、medal、sandbox、bossRush 等十余个)由 serde 忽略;模型只覆盖当前需要展示/计算的部分。
位置:arknights.rs:135
用途:data.status。
字段:name(形如 Sciencekill#1309)、uid(渠道角色 uid,不等于 森空岛 userId)、level、exp(ArknightsProgress)、ap(ArknightsAp)、avatar(Option<ArknightsAvatar>)、char_cnt、skin_cnt、furniture_cnt、main_stage_progress(如 main_02-09)、resume、secretary(Option<ArknightsSecretary>)、server_name(实测可能为空串)、register_ts、last_online_ts、store_ts(森空岛最后一次同步游戏数据的时间)、subscription_end
struct ArknightsAp / struct ArknightsAvatar / struct ArknightsSecretary
ArknightsAp(arknights.rs:163):current / max / last_ap_add_time(前端按 1/6/60 每秒推算当前理智)/ complete_recovery_time
ArknightsAvatar(arknights.rs:176):id / kind(serde type;实测取值 ICON、ASSISTANT)/ url(web.hycdn.cn)/ base64(接口不返回 ,由 ArknightsService::cache_player_info 下载后填充)
ArknightsSecretary(arknights.rs:192):char_id / skin_id(看板干员)
struct ArknightsBuilding 及其子结构
位置:arknights.rs:283
用途:data.building。字段:labor(Option<ArknightsLabor>)、hire(Option<ArknightsHire>,实测可为 null )、training(Option<ArknightsTraining>,实测可为 null )、tired_chars、control / powers / tradings / manufactures / dormitories / meeting(均 Vec<ArknightsRoomSegment>,经 one_or_many 转换 )
子结构
位置
字段
ArknightsLabor
arknights.rs:311
value / max_value / remain_secs(按 lastUpdateTime 计算)/ last_update_time(无人机)
ArknightsHire
arknights.rs:322
refresh_count(上限 3)/ complete_work_time(办公室刷新)
ArknightsTraining
arknights.rs:331
trainee(Option)/ trainer(Option)/ speed(f64 )/ remain_point(f64 )/ remain_secs(按请求时间计算)
ArknightsHire
arknights.rs:322
refresh_count(上限 3)/ complete_work_time / level / slot_id / slot_state / state / chars
ArknightsTrainee
arknights.rs:346
char_id / target_skill(-1 表示空位)
ArknightsTrainer
arknights.rs:356
char_id
ArknightsTiredChar
arknights.rs:363
char_id / ap / index / room_slot_id / last_ap_add_time / work_time
ArknightsRoomSegment
arknights.rs:381
chars / level / slot_id / slot_state(仅 control)/ capacity / weight / formula_id / remain / complete / complete_work_time / last_update_time / speed / comfort —— 不同设施给的字段不同,全部走容错缺省
ArknightsRoomChar
arknights.rs:414
char_id / ap(ap / 360000 = 心情点数)/ index / last_ap_add_time / work_time
⚠️ 浮点字段 :training.speed / training.remain_point / room_segment.speed 实测是浮点 (B 服给 1.35 / 0.45 / 1.53,官服恰好给整数)。声明成整型会让整个 player/info 解析失败 —— 接口 code=0、字段看着都对,但服务层拿到 Err,前端表现为「等级 0、没有头像」。回归测试见 training_accepts_float_speed_and_remain_point / room_speed_accepts_float。
⚠️ 设施是「对象或数组」混用的 :实测同一响应里 control / meeting 是对象 ,而 powers / tradings / manufactures / dormitories 是数组 。one_or_many(arknights.rs:11)统一收敛成 Vec,不兼容的话整个 player/info 都会解析失败。
struct ArknightsChar 及其子结构
ArknightsChar(arknights.rs:206):char_id / level / evolve_phase(0/1/2)/ potential_rank(0..5)/ main_skill_lvl(1..7)/ favor_percent / gain_time / exp / rarity / default_skill_id / default_equip_id / skin_id / skills / equip
ArknightsSkill(arknights.rs:243):id / specialize_level(0..3,player/info 用这个名字 )
ArknightsEquip(arknights.rs:254):id / level / locked
struct ArknightsRoutine / ArknightsCampaign / ArknightsTower / ArknightsTowerReward / ArknightsRecruitSlot / ArknightsProgress
ArknightsProgress(arknights.rs:26):current / total(通用进度对)
ArknightsRoutine(arknights.rs:266):daily / weekly
ArknightsCampaign(arknights.rs:275):reward / records(未建模,原样保留)
ArknightsTower(arknights.rs:283 → 见上):reward / records
ArknightsTowerReward:higher_item / lower_item / term_ts(本期结束时间)
ArknightsRecruitSlot(arknights.rs:256):state(2 = 招募中)/ start_ts / finish_ts
struct ArknightsCultivate 及其子结构
位置:arknights.rs:444
用途:GET /api/v1/game/cultivate/player?uid= 的 data。干员养成 player/info 已经全给(还多了信赖/皮肤),该接口唯一增量是 items(仓库) 。
字段:characters(Vec<ArknightsCultivateChar>)、items(Vec<ArknightsItem>)
ArknightsCultivateChar:id / level / evolve_phase / potential_rank / main_skill_level / skills / equips
ArknightsCultivateSkill:id / level(该接口用 level,不是 specializeLevel )
ArknightsCultivateEquip:id / level
ArknightsItem:id / count(字符串 ,如 "56")
struct ArknightsAttendance 及其子结构
位置:arknights.rs:542
用途:GET /api/v1/game/attendance?gameId=1&uid= 的 data。
字段:calendar(Vec<ArknightsCalendarEntry>)、records(Vec<ArknightsCheckinRecord>)、resource_info_map(物品 id → 静态信息,接口不含 icon )、current_ts(实测为字符串 ,经 string_or_i64 接受两种写法)、first(Option<Value>,实测为 null)、has_today / today_index / tomorrow_index(接口不返回 ,由服务层 fill_derived 算好后下发)
ArknightsCalendarEntry:resource_id / count / kind(serde type,实测 daily)/ done / available
ArknightsCheckinRecord:resource_id / count / ts(字符串 时间戳)/ kind
⚠️ calendar 是「累计 30 格领取轨道」,不是日期网格 (2026-11-11 真机抓包确认)。
抓包时刻 11 号 22:03、签到前:只有下标 1 (4001×500)是 available:true, done:false,
下标 0(2002×3)done:true,下标 2 之后全 false。点签到后 POST 返回的 awards
正是下标 1 那格。所以「11 号」≠「下标 10」,用「今天几号 - 1」索引日历必然误判成未签到
(早先 detectSignedToday 就是这么错的)。
正确判据:存在 available && !done 的格子 ⇔ 今天还能领 ⇔ 今天没签 。
实现见 signed_today() / claimable_index() / last_done_index();回归测试
attendance_signed_today_uses_claimable_slot_not_day_of_month。
同一 resourceId 在不同格的数量不同 (4001 是 500/1000 混排),数量必须逐格取,
不能按 id 累加(测试 attendance_reward_count_is_per_slot_not_accumulated)。
impl ArknightsAttendance 的方法:
方法
位置
说明
claimable_index()
arknights.rs:572
第一个 available && !done 的下标
last_done_index()
arknights.rs:577
最后一个 done 的下标
has_record_today()
arknights.rs:582
records[].ts 是否落在 currentTs 当天(本地时区)
signed_today()
arknights.rs:601
今天是否已签(有可领格 ⇒ 未签;空日历退回看 records)
today_slot() / tomorrow_slot()
arknights.rs:616 / 620
今日 / 明日奖励下标
fill_derived()
arknights.rs:627
填 has_today / today_index / tomorrow_index
fill_resource_icons()
arknights.rs:640
给 resourceInfoMap 每项补 icon(CDN 地址)
reward_of(index)
arknights.rs:665
取某格奖励(数量取该格自己的 count)
struct ArknightsAttendanceReward
位置:arknights.rs:691 — 日历格解析后的奖励行:resource_id / name / icon / count / kind / done / available
struct ArknightsAward / ArknightsAwardResource / ArknightsAttendanceResult
ArknightsAward(arknights.rs:741):resource / count / kind(serde type,实测 daily)
ArknightsAwardResource(arknights.rs:755):id / kind(serde type,如 GOLD/MATERIAL)/ name / rarity / icon(接口不返回 ,由 fill_icon() 按 id 拼)
ArknightsAttendanceResult(arknights.rs:798):POST /api/v1/game/attendance 的完整结果 —— ts(字符串时间戳)/ awards[] / tomorrow_awards[](数组 ,经 one_or_many_default 兼容单对象与缺失)/ resource_info_map / already_signed / code / message
impl ArknightsAwardResource::fill_icon() / impl ArknightsAward::fill_icon():按 id 拼 https://web.hycdn.cn/arknights/game/assets/item/{id}.png
⚠️ tomorrowAwards 是数组 (实测一项)。早先误当单对象建模,serde 会解析失败/丢失。
用 PowerShell 的 ConvertFrom-Json 直觉判断成对象也会误导 —— 以原始 JSON 为准。
图标 URL:ARKNIGHTS_ITEM_ICON_BASE / arknights_item_icon_url()
位置:arknights.rs:25 / 29
签到接口的 resourceInfoMap 与 awards[].resource 都不下发 icon ,一律按 resourceId 拼:
https://web.hycdn.cn/arknights/game/assets/item/{resourceId}.png
已实测 2003 / 4001 / 3302 / 31033 返回 200(999999 → 404)
fn one_or_many<'de, D, T> — arknights.rs:39:T 或 Vec<T> 都接受,统一成 Vec<T>。用于基建设施(对象/数组混用)。
fn one_or_many_default<'de, D, T> — arknights.rs:62:数组 / 单对象 / null / 缺失四种都收敛成 Vec<T>,用于 tomorrowAwards。直接走 serde_json::Value 分发,不用 #[serde(untagged)](untagged 会吞错误、难定位)。
fn string_or_i64<'de, D> — arknights.rs:88:数字或数字字符串都接受,转 i64。用于 attendance.currentTs / ts。
fn local_day_key(ts) — arknights.rs:703:Unix 秒 → 本地时区 YYYY-MM-DD。
测试(#[cfg(test)] mod tests)
离线 ,用真实抓取的响应夹具(tests/fixtures/arknights/):
夹具
来源
player_info.json / cultivate.json
真实 player/info / cultivate/player 响应(昵称/uid 已换成占位值)
attendance.json
2026-11-11 签到前 的真实 GET /api/v1/game/attendance 响应(30 格完整)
attendance_signed.json
同上,按签到后状态派生(下标 1 变 done、全表无 available)
attendance_result.json
2026-11-11 点击签到后 的真实 POST /api/v1/game/attendance 响应
测试清单:player_info_parses_all_modelled_fields(逐字段断言,防「字段名对不上 → 静默走 default → 界面空白」)、player_info_tolerates_missing_building、player_info_accepts_hire_and_training_when_present、player_info_round_trips_without_losing_fields、cultivate_parses_characters_and_items、attendance_parses_calendar_records_and_resource_map、attendance_signed_today_uses_claimable_slot_not_day_of_month、attendance_result_parses_awards_and_tomorrow、attendance_result_marks_already_signed_when_code_nonzero、attendance_reward_count_is_per_slot_not_accumulated、attendance_detects_record_within_today、attendance_tolerates_missing_optional_parts、attendance_falls_back_to_records_when_calendar_empty、item_icon_url_uses_resource_id、training_accepts_float_speed_and_remain_point、room_speed_accepts_float。