feat(editor): 完成英雄配置编辑器全功能开发

本提交新增完整的英雄配置可视化编辑器:
1.  初始化前后端项目结构,配置monorepo工作区
2.  实现后端API服务,支持读取游戏配置、导出hexport.ts文件
3.  开发前端Vue应用,包含完整的英雄增删改、属性配置、技能编辑功能
4.  实现多类型编辑器组件:基础属性、普攻/大招编辑、触发技能、光环、复活、属性加成等
5.  清理冗余的配置元数据文件
This commit is contained in:
panFD
2026-09-02 23:35:40 +08:00
parent 6fed56d3c7
commit a2dc40997c
28 changed files with 4641 additions and 66 deletions

View File

@@ -0,0 +1,56 @@
<template>
<div class="override-editor">
<div v-for="(item, idx) in rows" :key="idx" class="override-row">
<el-select v-model="item.key" placeholder="字段" size="small" style="width: 200px" filterable>
<el-option v-for="k in availableKeys(idx)" :key="k.key" :label="k.label" :value="k.key" />
</el-select>
<el-input-number v-model="item.value" size="small" :controls="false" style="width: 120px" />
<el-button type="danger" size="small" text @click="remove(idx)">删除</el-button>
</div>
<el-button size="small" @click="add">+ 添加覆盖</el-button>
</div>
</template>
<script setup>
import { ref, watch } from 'vue'
import { OVERRIDE_KEYS } from '../constants'
const props = defineProps({ modelValue: { type: Object, default: () => ({}) } })
const emit = defineEmits(['update:modelValue'])
// 本地行数组,允许 key 为空
const rows = ref(Object.entries(props.modelValue || {}).map(([key, value]) => ({ key, value })))
// 外部 modelValue 变化时同步(如切换英雄)
watch(() => props.modelValue, (v) => {
const next = Object.entries(v || {}).map(([key, value]) => ({ key, value }))
// 简单比较,避免输入时循环
if (JSON.stringify(next) !== JSON.stringify(rows.value.filter(r => r.key))) {
rows.value = next
}
}, { deep: true })
// 每次行变化都尝试同步(过滤空 key)
watch(rows, (arr) => {
const obj = {}
for (const it of arr) if (it.key) obj[it.key] = it.value
emit('update:modelValue', obj)
}, { deep: true })
// 已选中的 key 不再出现在其他行的下拉中
function availableKeys(idx) {
const used = new Set(rows.value.map((r, i) => (i === idx ? null : r.key)).filter(Boolean))
return OVERRIDE_KEYS.filter((k) => !used.has(k.key))
}
function add() {
rows.value.push({ key: '', value: 0 })
}
function remove(idx) {
rows.value.splice(idx, 1)
}
</script>
<style scoped>
.override-row { display: flex; gap: 8px; margin-bottom: 6px; align-items: center; }
</style>