feat: 新增技能级局部更新的 PATCH 接口
新增 PATCH /api/heroes/:uuid/skills/:skillUuid 接口,支持按层级合并技能字段及 lv_entries,避免整表替换技能数据。同时更新 API 文档,说明该接口的功能与使用方式。
This commit is contained in:
@@ -214,6 +214,87 @@ app.delete('/api/heroes/:uuid', async (req, res) => {
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* 技能级局部更新:PATCH /api/heroes/:uuid/skills/:skillUuid
|
||||
* 支持对技能字段及 lv_entries 按 lv 合并,避免整表替换 skills 数组。
|
||||
*
|
||||
* body 格式:
|
||||
* {
|
||||
* name?, cd?, cdExpr?, desc?, // 技能基础字段,存在则覆盖
|
||||
* overrides?, // 与现有 overrides 浅合并(不是替换)
|
||||
* lv_entries?: [ // 按 lv 合并:存在则更新该档,不存在则新增
|
||||
* { lv, s_lv?, overrides?, desc? }
|
||||
* ]
|
||||
* }
|
||||
*/
|
||||
app.patch('/api/heroes/:uuid/skills/:skillUuid', async (req, res) => {
|
||||
try {
|
||||
if (!(await guardVersion(res))) return
|
||||
const uuid = Number(req.params.uuid)
|
||||
const skillUuid = Number(req.params.skillUuid)
|
||||
if (Number.isNaN(uuid) || Number.isNaN(skillUuid)) {
|
||||
return res.status(400).json({ error: 'uuid 与 skillUuid 必须为数字' })
|
||||
}
|
||||
const patch = req.body
|
||||
if (!patch || typeof patch !== 'object') {
|
||||
return res.status(400).json({ error: 'body 必须为技能补丁对象' })
|
||||
}
|
||||
|
||||
const heroes = await store.getHeroes()
|
||||
const hIdx = heroes.findIndex((h) => h.uuid === uuid)
|
||||
if (hIdx < 0) return res.status(404).json({ error: `英雄 ${uuid} 不存在` })
|
||||
|
||||
const hero = heroes[hIdx]
|
||||
const sIdx = hero.skills.findIndex((s) => s.uuid === skillUuid)
|
||||
if (sIdx < 0) return res.status(404).json({ error: `英雄 ${uuid} 不存在技能 ${skillUuid}` })
|
||||
|
||||
const skill = hero.skills[sIdx]
|
||||
|
||||
// 基础字段直接覆盖
|
||||
if (patch.name !== undefined) skill.name = patch.name
|
||||
if (patch.cd !== undefined) skill.cd = patch.cd
|
||||
if (patch.cdExpr !== undefined) skill.cdExpr = patch.cdExpr
|
||||
if (patch.desc !== undefined) skill.desc = patch.desc
|
||||
|
||||
// overrides 浅合并(不是替换)
|
||||
if (patch.overrides && typeof patch.overrides === 'object') {
|
||||
skill.overrides = { ...skill.overrides, ...patch.overrides }
|
||||
}
|
||||
|
||||
// lv_entries 按 lv 合并:同 lv 更新,不同 lv 新增
|
||||
if (Array.isArray(patch.lv_entries)) {
|
||||
if (!Array.isArray(skill.lv_entries)) skill.lv_entries = []
|
||||
for (const entry of patch.lv_entries) {
|
||||
if (!entry || typeof entry !== 'object') continue
|
||||
const lv = entry.lv
|
||||
if (lv === undefined) continue
|
||||
const eIdx = skill.lv_entries.findIndex((e) => e.lv === lv)
|
||||
if (eIdx >= 0) {
|
||||
// 同 lv:浅合并 overrides,覆盖其他字段
|
||||
const existing = skill.lv_entries[eIdx]
|
||||
skill.lv_entries[eIdx] = {
|
||||
...existing,
|
||||
...entry,
|
||||
overrides: entry.overrides
|
||||
? { ...existing.overrides, ...entry.overrides }
|
||||
: existing.overrides,
|
||||
}
|
||||
} else {
|
||||
// 新 lv:直接插入
|
||||
skill.lv_entries.push(entry)
|
||||
}
|
||||
}
|
||||
// 按 lv 升序排序,保持数据整洁
|
||||
skill.lv_entries.sort((a, b) => a.lv - b.lv)
|
||||
}
|
||||
|
||||
await store.saveHeroes(heroes)
|
||||
res.json({ ok: true, uuid, skillUuid, action: 'skill_patched' })
|
||||
} catch (e) {
|
||||
res.status(500).json({ error: String(e?.message || e) })
|
||||
}
|
||||
})
|
||||
|
||||
/** 预设库:GET 从线上库读取 */
|
||||
app.get('/api/templates', async (_req, res) => {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user