78 lines
3.3 KiB
Vue
78 lines
3.3 KiB
Vue
<script setup lang="ts">
|
|
import AppForm from '../../../components/ui/AppForm.vue'
|
|
import { NFormItem } from 'naive-ui'
|
|
import { NButton, NCheckbox, NInput } from 'naive-ui'
|
|
import { computed, reactive, ref, watch } from 'vue'
|
|
import type { SaveIdentityInput, SubjectIdentity } from '../types'
|
|
|
|
/** 身份文本草稿不随轮询覆盖;父页面切换主体或保存成功后重建编辑器。 */
|
|
const props = defineProps<{ identity: SubjectIdentity | null; disabled: boolean; module: string }>()
|
|
const emit = defineEmits<{ save: [input: SaveIdentityInput]; dirty: [value: boolean] }>()
|
|
const form = reactive({ description: '', generationPrompt: '', isLocked: false })
|
|
const baseline = ref('')
|
|
const dirty = computed(() => JSON.stringify(form) !== baseline.value)
|
|
watch(
|
|
() => props.identity,
|
|
value => {
|
|
if (baseline.value && dirty.value) return
|
|
Object.assign(form, {
|
|
description: value?.description ?? '',
|
|
generationPrompt: value?.generationPrompt ?? '',
|
|
isLocked: value?.isLocked ?? false
|
|
})
|
|
baseline.value = JSON.stringify(form)
|
|
},
|
|
{ immediate: true }
|
|
)
|
|
watch(dirty, value => emit('dirty', value), { immediate: true })
|
|
|
|
/** 保存用户输入;空文本允许保存,但生图入口仍会检查必要 Prompt。 */
|
|
function save() {
|
|
if (!props.disabled) emit('save', { ...form })
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<AppForm :model="form" :disabled="disabled" class="mt-5" @submit="save">
|
|
<fieldset :disabled="disabled" class="space-y-4">
|
|
<NFormItem class="block" path="description" label="身份描述" :label-props="{ for: 'identity-description' }"
|
|
><NInput
|
|
:disabled="disabled"
|
|
placeholder="只描述跨形态不变的面部、结构、材质等特征"
|
|
:input-props="{ id: 'identity-description' }"
|
|
class="min-h-20"
|
|
v-model:value="form.description"
|
|
type="textarea"
|
|
:autosize="{ minRows: 2, maxRows: 8 }"
|
|
></NInput>
|
|
</NFormItem>
|
|
<NFormItem
|
|
class="block"
|
|
path="generationPrompt"
|
|
label="核心提示词"
|
|
:label-props="{ for: 'identity-prompt' }"
|
|
><NInput
|
|
:disabled="disabled"
|
|
placeholder="不固定某一形态的服装、伤势或临时状态"
|
|
:input-props="{ id: 'identity-prompt' }"
|
|
class="min-h-24"
|
|
v-model:value="form.generationPrompt"
|
|
type="textarea"
|
|
:autosize="{ minRows: 2, maxRows: 8 }"
|
|
></NInput>
|
|
</NFormItem>
|
|
<NCheckbox
|
|
:disabled="disabled"
|
|
id="identity-lock"
|
|
v-model:checked="form.isLocked"
|
|
class="flex items-start gap-2 text-xs leading-6"
|
|
>{{ module === 'character' ? '锁定演员身份' : '锁定身份' }}</NCheckbox
|
|
>
|
|
<div class="page-form-actions">
|
|
<NButton :disabled="disabled" type="primary" attr-type="submit">保存主体身份</NButton>
|
|
<span v-if="dirty" class="text-xs text-muted">有未保存修改</span>
|
|
</div>
|
|
</fieldset>
|
|
</AppForm>
|
|
</template>
|