add relationship in front
This commit is contained in:
@@ -694,6 +694,7 @@ class CreateAvatarRequest(BaseModel):
|
||||
auxiliary_id: Optional[int] = None
|
||||
alignment: Optional[str] = None
|
||||
appearance: Optional[int] = None
|
||||
relations: Optional[List[dict]] = None
|
||||
|
||||
class DeleteAvatarRequest(BaseModel):
|
||||
avatar_id: str
|
||||
@@ -883,7 +884,8 @@ def create_avatar(req: CreateAvatarRequest):
|
||||
technique=req.technique_id,
|
||||
weapon=req.weapon_id,
|
||||
auxiliary=req.auxiliary_id,
|
||||
appearance=req.appearance
|
||||
appearance=req.appearance,
|
||||
relations=req.relations
|
||||
)
|
||||
|
||||
if req.pic_id is not None:
|
||||
@@ -899,10 +901,9 @@ def create_avatar(req: CreateAvatarRequest):
|
||||
if req.appearance is not None:
|
||||
avatar.appearance = get_appearance_by_level(req.appearance)
|
||||
|
||||
# 清空系统自动生成的关系,保持用户自定义角色独立
|
||||
existing_relations = list(getattr(avatar, "relations", {}).keys())
|
||||
for other in existing_relations:
|
||||
avatar.clear_relation(other)
|
||||
# 关系已经在 create_avatar_from_request 中根据参数设置好了,
|
||||
# 且该函数内部调用 MortalPlanner 时已经指定 allow_relations=False,不会生成随机关系。
|
||||
# 因此这里不需要再清空关系,否则会把自己选的关系删掉。
|
||||
|
||||
if req.alignment:
|
||||
avatar.alignment = Alignment.from_str(req.alignment)
|
||||
|
||||
@@ -859,6 +859,7 @@ def create_avatar_from_request(
|
||||
auxiliary: Union[str, int, Auxiliary, None] = None,
|
||||
personas: Union[str, int, Persona, List[Union[str, int, Persona]], None] = None,
|
||||
appearance: Optional[int] = None,
|
||||
relations: Optional[List[Dict[str, str]]] = None,
|
||||
) -> Avatar:
|
||||
"""
|
||||
供前端使用的角色创建入口:支持字符串/ID 参数,且默认不生成亲友关系。
|
||||
@@ -927,4 +928,28 @@ def create_avatar_from_request(
|
||||
overrides=overrides if overrides else None,
|
||||
)
|
||||
|
||||
if relations:
|
||||
for rel_item in relations:
|
||||
target_id = rel_item.get('target_id')
|
||||
rel_type = rel_item.get('relation')
|
||||
|
||||
if not target_id or not rel_type:
|
||||
continue
|
||||
|
||||
# 尝试转为字符串ID
|
||||
t_id_str = str(target_id)
|
||||
target = world.avatar_manager.avatars.get(t_id_str)
|
||||
if not target:
|
||||
continue
|
||||
|
||||
# 解析关系
|
||||
rel_enum = None
|
||||
for r in Relation:
|
||||
if r.value == rel_type:
|
||||
rel_enum = r
|
||||
break
|
||||
|
||||
if rel_enum:
|
||||
avatar.set_relation(target, rel_enum)
|
||||
|
||||
return avatar
|
||||
@@ -47,6 +47,7 @@ export interface CreateAvatarParams {
|
||||
auxiliary_id?: number;
|
||||
alignment?: string;
|
||||
appearance?: number;
|
||||
relations?: Array<{ target_id: string; relation: string }>;
|
||||
}
|
||||
|
||||
export interface PhenomenonDTO {
|
||||
|
||||
@@ -38,9 +38,21 @@ const createForm = ref<CreateAvatarParams>({
|
||||
weapon_id: undefined,
|
||||
auxiliary_id: undefined,
|
||||
alignment: undefined,
|
||||
appearance: 7
|
||||
appearance: 7,
|
||||
relations: []
|
||||
})
|
||||
|
||||
const relationOptions = [
|
||||
{ label: '父母', value: 'parent' },
|
||||
{ label: '子女', value: 'child' },
|
||||
{ label: '兄弟姐妹', value: 'sibling' },
|
||||
{ label: '师傅', value: 'master' },
|
||||
{ label: '徒弟', value: 'apprentice' },
|
||||
{ label: '道侣', value: 'lovers' },
|
||||
{ label: '朋友', value: 'friend' },
|
||||
{ label: '仇人', value: 'enemy' }
|
||||
]
|
||||
|
||||
// --- Delete Avatar State ---
|
||||
const avatarList = ref<SimpleAvatarDTO[]>([])
|
||||
const avatarSearch = ref('')
|
||||
@@ -114,6 +126,24 @@ const alignmentOptions = computed(() => {
|
||||
}))
|
||||
})
|
||||
|
||||
const avatarOptions = computed(() => {
|
||||
return avatarList.value.map(a => ({
|
||||
label: `[${a.sect_name}] ${a.name}`,
|
||||
value: a.id
|
||||
}))
|
||||
})
|
||||
|
||||
function addRelation() {
|
||||
if (!createForm.value.relations) {
|
||||
createForm.value.relations = []
|
||||
}
|
||||
createForm.value.relations.push({ target_id: '', relation: 'friend' })
|
||||
}
|
||||
|
||||
function removeRelation(index: number) {
|
||||
createForm.value.relations?.splice(index, 1)
|
||||
}
|
||||
|
||||
// --- Actions ---
|
||||
|
||||
async function fetchSaves() {
|
||||
@@ -214,7 +244,8 @@ async function handleCreateAvatar() {
|
||||
weapon_id: undefined,
|
||||
auxiliary_id: undefined,
|
||||
alignment: undefined,
|
||||
appearance: 7
|
||||
appearance: 7,
|
||||
relations: []
|
||||
}
|
||||
} catch (e) {
|
||||
message.error('创建失败: ' + String(e))
|
||||
@@ -247,6 +278,7 @@ function switchTab(tab: typeof activeTab.value) {
|
||||
fetchSaves()
|
||||
} else if (tab === 'create') {
|
||||
fetchGameData()
|
||||
fetchAvatarList()
|
||||
} else if (tab === 'delete') {
|
||||
fetchAvatarList()
|
||||
}
|
||||
@@ -395,6 +427,27 @@ onMounted(() => {
|
||||
<n-form-item label="辅助装备">
|
||||
<n-select v-model:value="createForm.auxiliary_id" :options="auxiliaryOptions" placeholder="选择辅助装备 (可留空)" clearable />
|
||||
</n-form-item>
|
||||
<n-form-item label="人际关系">
|
||||
<div class="relations-container">
|
||||
<div v-for="(rel, index) in createForm.relations" :key="index" class="relation-row">
|
||||
<n-select
|
||||
v-model:value="rel.target_id"
|
||||
:options="avatarOptions"
|
||||
placeholder="选择角色"
|
||||
filterable
|
||||
style="width: 160px"
|
||||
/>
|
||||
<n-select
|
||||
v-model:value="rel.relation"
|
||||
:options="relationOptions"
|
||||
placeholder="关系"
|
||||
style="width: 100px"
|
||||
/>
|
||||
<n-button @click="removeRelation(index)" circle size="small" type="error">-</n-button>
|
||||
</div>
|
||||
<n-button @click="addRelation" size="small" dashed style="width: 100%">+ 添加关系</n-button>
|
||||
</div>
|
||||
</n-form-item>
|
||||
<div class="actions">
|
||||
<n-button type="primary" @click="handleCreateAvatar" block>创建角色</n-button>
|
||||
</div>
|
||||
@@ -753,4 +806,17 @@ onMounted(() => {
|
||||
text-align: right;
|
||||
color: #ddd;
|
||||
}
|
||||
|
||||
.relations-container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.relation-row {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user