- 角色管理:CRUD API + 卡片网格UI,每个角色约200字描述 - 世界观设定:单篇长文编辑器,建议500字以上 - 章节管理:CRUD + 排序 API,左右分栏编辑器,单章5000字上限 - AI工具调用:支持工具审批流程和结构化工具调用 - 小说详情页新增章节、角色、世界观入口按钮 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
80 lines
1.9 KiB
Vue
80 lines
1.9 KiB
Vue
<script setup lang="ts">
|
|
import { ref, watch, computed } from 'vue'
|
|
import type { Chapter } from '@/types/chapter'
|
|
import BaseModal from '@/components/ui/BaseModal.vue'
|
|
import BaseInput from '@/components/ui/BaseInput.vue'
|
|
import BaseButton from '@/components/ui/BaseButton.vue'
|
|
|
|
const props = defineProps<{
|
|
show: boolean
|
|
chapter: Chapter | null
|
|
saving: boolean
|
|
}>()
|
|
|
|
const emit = defineEmits<{
|
|
submit: [data: { title: string }]
|
|
close: []
|
|
}>()
|
|
|
|
const title = ref('')
|
|
|
|
const isEdit = computed(() => !!props.chapter)
|
|
const modalTitle = computed(() => isEdit.value ? '重命名章节' : '新建章节')
|
|
const canSubmit = computed(() => title.value.trim().length > 0 && !props.saving)
|
|
|
|
watch(() => props.show, (val) => {
|
|
if (val) {
|
|
title.value = props.chapter?.title ?? ''
|
|
}
|
|
})
|
|
|
|
function handleSubmit() {
|
|
if (!canSubmit.value) return
|
|
emit('submit', { title: title.value.trim() })
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<BaseModal :show="show" @close="emit('close')">
|
|
<form class="chapter-form" @submit.prevent="handleSubmit">
|
|
<h2 class="form-title">{{ modalTitle }}</h2>
|
|
|
|
<BaseInput
|
|
v-model="title"
|
|
label="章节标题"
|
|
:maxlength="200"
|
|
required
|
|
/>
|
|
|
|
<div class="form-actions">
|
|
<BaseButton variant="secondary" type="button" @click="emit('close')">取消</BaseButton>
|
|
<BaseButton variant="primary" type="submit" :loading="saving" :disabled="!canSubmit">
|
|
{{ isEdit ? '保存' : '创建' }}
|
|
</BaseButton>
|
|
</div>
|
|
</form>
|
|
</BaseModal>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.chapter-form {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--space-lg);
|
|
}
|
|
|
|
.form-title {
|
|
font-family: var(--font-display);
|
|
font-size: 1.4rem;
|
|
font-weight: 700;
|
|
color: var(--ink-900);
|
|
}
|
|
|
|
.form-actions {
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
gap: var(--space-sm);
|
|
padding-top: var(--space-sm);
|
|
}
|
|
</style>
|