feat(web): 新增 timed_buff_id 覆写组件支持与 buff 列表配置

1. 扩展 SUPPORT_ULT 技能列表,新增6517号技能
2. 为 OVERRIDE_KEYS 添加buff类型标记与注释说明
3. 新增buffOptions参数透传机制,实现timed_buff_id下拉选择
4. 新增buff类型覆写编辑器,支持搜索创建与类型归一化
This commit is contained in:
pan
2026-09-07 12:45:14 +08:00
parent 922ca7318d
commit 5fc743dbe3
5 changed files with 52 additions and 12 deletions

View File

@@ -116,14 +116,14 @@
<!-- 普攻 --> <!-- 普攻 -->
<div class="panel"> <div class="panel">
<h3>普攻 skills[0]</h3> <h3>普攻 skills[0]</h3>
<SkillEditor v-if="basicSkill" :skill="basicSkill" :options="basicSkillOptions" :skill-options="allSkills" :basic-lv2="true" /> <SkillEditor v-if="basicSkill" :skill="basicSkill" :options="basicSkillOptions" :skill-options="allSkills" :buff-options="buffOptions" :basic-lv2="true" />
<el-button v-else size="small" type="primary" @click="addBasicSkill">+ 添加普攻</el-button> <el-button v-else size="small" type="primary" @click="addBasicSkill">+ 添加普攻</el-button>
</div> </div>
<!-- 大招 --> <!-- 大招 -->
<div class="panel"> <div class="panel">
<h3>大招 skills[1]</h3> <h3>大招 skills[1]</h3>
<SkillEditor v-if="ultSkill" :skill="ultSkill" :options="ultSkillOptions" :skill-options="allSkills" :is-ult="true" /> <SkillEditor v-if="ultSkill" :skill="ultSkill" :options="ultSkillOptions" :skill-options="allSkills" :buff-options="buffOptions" :is-ult="true" />
<el-button v-else size="small" type="primary" @click="addUltSkill">+ 添加大招</el-button> <el-button v-else size="small" type="primary" @click="addUltSkill">+ 添加大招</el-button>
</div> </div>
@@ -131,10 +131,10 @@
<div class="panel"> <div class="panel">
<h3>触发技能(lv4 激活)</h3> <h3>触发技能(lv4 激活)</h3>
<el-tabs> <el-tabs>
<el-tab-pane label="atking 攻击后"><TriggerGroupEditor :model="current.atking" :skill-options="allSkills" :skill-map="skillMap" /></el-tab-pane> <el-tab-pane label="atking 攻击后"><TriggerGroupEditor :model="current.atking" :skill-options="allSkills" :skill-map="skillMap" :buff-options="buffOptions" /></el-tab-pane>
<el-tab-pane label="atked 受击后"><TriggerGroupEditor :model="current.atked" :skill-options="allSkills" :skill-map="skillMap" /></el-tab-pane> <el-tab-pane label="atked 受击后"><TriggerGroupEditor :model="current.atked" :skill-options="allSkills" :skill-map="skillMap" :buff-options="buffOptions" /></el-tab-pane>
<el-tab-pane label="fstart 战斗开始"><TriggerGroupEditor :model="current.fstart" :skill-options="allSkills" :skill-map="skillMap" /></el-tab-pane> <el-tab-pane label="fstart 战斗开始"><TriggerGroupEditor :model="current.fstart" :skill-options="allSkills" :skill-map="skillMap" :buff-options="buffOptions" /></el-tab-pane>
<el-tab-pane label="dead 死亡后"><TriggerGroupEditor :model="current.dead" :skill-options="allSkills" :skill-map="skillMap" /></el-tab-pane> <el-tab-pane label="dead 死亡后"><TriggerGroupEditor :model="current.dead" :skill-options="allSkills" :skill-map="skillMap" :buff-options="buffOptions" /></el-tab-pane>
</el-tabs> </el-tabs>
</div> </div>
@@ -203,6 +203,8 @@ const current = computed(() => heroes.value[activeIdx.value])
const skillMap = computed(() => meta.value?.SkillSet || {}) const skillMap = computed(() => meta.value?.SkillSet || {})
const allSkills = computed(() => Object.values(skillMap.value).sort((a, b) => a.uuid - b.uuid)) const allSkills = computed(() => Object.values(skillMap.value).sort((a, b) => a.uuid - b.uuid))
const fieldOptions = computed(() => Object.values(meta.value?.FieldSkillSet || {}).sort((a, b) => a.uuid - b.uuid)) const fieldOptions = computed(() => Object.values(meta.value?.FieldSkillSet || {}).sort((a, b) => a.uuid - b.uuid))
// buff 候选:timed_buff_id 覆写下拉用(BuffList 按 id 升序)
const buffOptions = computed(() => Object.values(meta.value?.BuffList || {}).sort((a, b) => a.id - b.id))
// 复活已纳入 dead 触发组,通过 dead 编辑器的 overrides 配置 revive_hp / revive_count // 复活已纳入 dead 触发组,通过 dead 编辑器的 overrides 配置 revive_hp / revive_count
const reviveOptions = computed(() => allSkills.value.filter((s) => s.uuid >= 6500 && s.uuid < 6600)) const reviveOptions = computed(() => allSkills.value.filter((s) => s.uuid >= 6500 && s.uuid < 6600))

View File

@@ -50,10 +50,27 @@
/> />
<div class="proc-skill-overrides"> <div class="proc-skill-overrides">
<span class="proc-skill-label">被触发技能覆写:</span> <span class="proc-skill-label">被触发技能覆写:</span>
<OverrideEditor v-model="item.value.overrides" :skill-options="skillOptions" /> <OverrideEditor v-model="item.value.overrides" :skill-options="skillOptions" :buff-options="buffOptions" />
</div> </div>
</div> </div>
</template> </template>
<!-- buff 型覆写(timed_buff_id):BuffList 下拉,副文本展示 buff info;allow-create 兼容 meta 未加载时手输 id -->
<el-select
v-else-if="isBuffKey(item.key)"
v-model="item.value"
placeholder="选择 buff id"
size="small"
style="width: 280px"
filterable
allow-create
default-first-option
@change="onBuffValueChange(item)"
>
<el-option v-for="b in buffOptions" :key="b.id" :label="`${b.id} ${b.name}`" :value="b.id">
<span>{{ b.id }} {{ b.name }}</span>
<span class="muted" style="float: right">{{ b.info }}</span>
</el-option>
</el-select>
<el-input-number v-else v-model="item.value" size="small" :controls="false" style="width: 120px" /> <el-input-number v-else v-model="item.value" size="small" :controls="false" style="width: 120px" />
<el-button type="danger" size="small" text @click="remove(idx)">删除</el-button> <el-button type="danger" size="small" text @click="remove(idx)">删除</el-button>
</div> </div>
@@ -69,6 +86,8 @@ const props = defineProps({
modelValue: { type: Object, default: () => ({}) }, modelValue: { type: Object, default: () => ({}) },
// 全部技能候选(proc_skill.s_uuid 下拉用),由 App 经 SkillEditor 透传 // 全部技能候选(proc_skill.s_uuid 下拉用),由 App 经 SkillEditor 透传
skillOptions: { type: Array, default: () => [] }, skillOptions: { type: Array, default: () => [] },
// 全部 buff 候选(timed_buff_id 下拉用),由 App 从 meta.BuffList 计算后透传
buffOptions: { type: Array, default: () => [] },
}) })
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
@@ -131,6 +150,18 @@ function enumOptions(key) {
return OVERRIDE_KEYS.find((k) => k.key === key)?.options || [] return OVERRIDE_KEYS.find((k) => k.key === key)?.options || []
} }
// 该覆写字段是否为 buff 型(timed_buff_id:值为 BuffList 配置 id)
function isBuffKey(key) {
return OVERRIDE_KEYS.find((k) => k.key === key)?.type === 'buff'
}
// allow-create 手输的 buff id 是字符串,归一化为数字,保证导出 TS 配置类型正确
function onBuffValueChange(item) {
if (typeof item.value === 'string' && item.value.trim() !== '' && !isNaN(Number(item.value))) {
item.value = Number(item.value)
}
}
// 对象型覆写行选中时初始化默认结构,避免 v-model 绑定到 undefined 子字段 // 对象型覆写行选中时初始化默认结构,避免 v-model 绑定到 undefined 子字段
function onKeyChange(item) { function onKeyChange(item) {
if (isObjectKey(item.key)) { if (isObjectKey(item.key)) {
@@ -140,6 +171,8 @@ function onKeyChange(item) {
} else if (isEnumKey(item.key)) { } else if (isEnumKey(item.key)) {
// 枚举默认取首个候选值 // 枚举默认取首个候选值
item.value = enumOptions(item.key)[0]?.value item.value = enumOptions(item.key)[0]?.value
} else if (isBuffKey(item.key)) {
item.value = undefined // buff id 必须显式选择,0 不是合法 id
} else { } else {
item.value = 0 item.value = 0
} }

View File

@@ -25,7 +25,7 @@
</el-form-item> </el-form-item>
</div> </div>
<el-form-item label="overrides"> <el-form-item label="overrides">
<OverrideEditor v-model="skill.overrides" :skill-options="skillOptions" /> <OverrideEditor v-model="skill.overrides" :skill-options="skillOptions" :buff-options="buffOptions" />
</el-form-item> </el-form-item>
<!-- 分档编辑:大招(is-ult)全档编辑;普攻(basic-lv2)仅 lv2 强化档(客户端独立技能图标消费) --> <!-- 分档编辑:大招(is-ult)全档编辑;普攻(basic-lv2)仅 lv2 强化档(客户端独立技能图标消费) -->
@@ -47,7 +47,7 @@
</el-form-item> </el-form-item>
</div> </div>
<el-form-item label="overrides"> <el-form-item label="overrides">
<OverrideEditor v-model="e.overrides" :skill-options="skillOptions" /> <OverrideEditor v-model="e.overrides" :skill-options="skillOptions" :buff-options="buffOptions" />
</el-form-item> </el-form-item>
<el-form-item label="描述"> <el-form-item label="描述">
<el-input v-model="e.desc" type="textarea" :rows="2" /> <el-input v-model="e.desc" type="textarea" :rows="2" />
@@ -72,6 +72,8 @@ const props = defineProps({
options: { type: Array, default: () => [] }, options: { type: Array, default: () => [] },
// 全部技能候选(proc_skill.s_uuid 下拉用),由 App 透传 // 全部技能候选(proc_skill.s_uuid 下拉用),由 App 透传
skillOptions: { type: Array, default: () => [] }, skillOptions: { type: Array, default: () => [] },
// 全部 buff 候选(timed_buff_id 下拉用),由 App 透传
buffOptions: { type: Array, default: () => [] },
isUlt: { type: Boolean, default: false }, isUlt: { type: Boolean, default: false },
// 普攻 lv2 强化档模式:仅允许配置单个 lv2 档(lv=2 / s_lv=2 锁定,禁用增删) // 普攻 lv2 强化档模式:仅允许配置单个 lv2 档(lv=2 / s_lv=2 锁定,禁用增删)
basicLv2: { type: Boolean, default: false }, basicLv2: { type: Boolean, default: false },

View File

@@ -23,7 +23,7 @@
</el-form-item> </el-form-item>
</div> </div>
<el-form-item label="overrides"> <el-form-item label="overrides">
<OverrideEditor v-model="entry.overrides" :skill-options="skillOptions" /> <OverrideEditor v-model="entry.overrides" :skill-options="skillOptions" :buff-options="buffOptions" />
</el-form-item> </el-form-item>
<el-form-item label="描述"> <el-form-item label="描述">
<el-input v-model="entry.desc" type="textarea" :rows="2" /> <el-input v-model="entry.desc" type="textarea" :rows="2" />
@@ -50,6 +50,8 @@ const props = defineProps({
model: { type: Object, required: true }, // TriggerGrouped model: { type: Object, required: true }, // TriggerGrouped
skillOptions: { type: Array, default: () => [] }, skillOptions: { type: Array, default: () => [] },
skillMap: { type: Object, default: () => ({}) }, skillMap: { type: Object, default: () => ({}) },
// 全部 buff 候选(timed_buff_id 下拉用),由 App 透传
buffOptions: { type: Array, default: () => [] },
}) })
const newSid = ref(null) const newSid = ref(null)

View File

@@ -52,7 +52,7 @@ export const ROLE_ULT_SKILL = {
} }
// 辅助类技能(任意职业可用作大招) // 辅助类技能(任意职业可用作大招)
export const SUPPORT_ULT = [6301, 6302, 6407, 6412, 6413, 6414, 6501, 6514, 6515, 6516] export const SUPPORT_ULT = [6301, 6302, 6407, 6412, 6413, 6414, 6501, 6514, 6515, 6516, 6517]
export function defaultHero() { export function defaultHero() {
return { return {
@@ -108,7 +108,8 @@ export const OVERRIDE_KEYS = [
{ key: 'para', label: 'para 麻痹概率' }, { key: 'para', label: 'para 麻痹概率' },
{ key: 'bck', label: 'bck 击退' }, { key: 'bck', label: 'bck 击退' },
{ key: 'bck_chance', label: 'bck_chance 击退概率' }, { key: 'bck_chance', label: 'bck_chance 击退概率' },
{ key: 'timed_buff_id', label: 'timed_buff_id 计时buff' }, // buff 型覆写:值为 BuffList 配置 id,前端用 meta.BuffList 渲染下拉(支持 allow-create 手输兜底)
{ key: 'timed_buff_id', label: 'timed_buff_id 计时buff', type: 'buff' },
{ key: 'buff_value', label: 'buff_value 修饰数值' }, { key: 'buff_value', label: 'buff_value 修饰数值' },
{ key: 'buff_duration', label: 'buff_duration 持续时间' }, { key: 'buff_duration', label: 'buff_duration 持续时间' },
{ key: 'buff_chance', label: 'buff_chance 附加概率' }, { key: 'buff_chance', label: 'buff_chance 附加概率' },