Files
short-drama-agent-front/src/features/projects/components/CreateProjectDialog.vue
T

130 lines
5.2 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import AppForm from '../../../components/ui/AppForm.vue'
import { NFormItem } from 'naive-ui'
import { requiredTextRule, integerRule } from '../../../lib/form-rules'
import { NAlert, NButton, NInput, NInputNumber } from 'naive-ui'
import { reactive, ref } from 'vue'
import { ArrowRight, LoaderCircle, Plus } from '@lucide/vue'
import { AppDialog } from '../../../components/ui'
import { projectsApi } from '../api'
import { errorMessage } from '../../../lib/http'
/** 新建剧本表单,202 成功后交由父级跳转,不在前端模拟生成。 */
const emit = defineEmits<{ created: [projectId: string] }>()
/** 新建剧本弹窗是否打开。 */
const open = ref(false)
/** 创建请求是否正在提交。 */
const busy = ref(false)
/** 创建请求的错误提示。 */
const error = ref('')
/** 与后端 POST /projects 入参一致的创建表单。 */
const form = reactive({ title: '', topic: '', style: '', episodeCount: 1 })
/** 校验项目标题、主题与正整数集数,禁止双击产生重复项目。 */
async function submit() {
if (busy.value) return
error.value = ''
busy.value = true
try {
const result = await projectsApi.create({
...form,
title: form.title.trim(),
topic: form.topic.trim(),
style: form.style.trim()
})
open.value = false
form.title = ''
form.topic = ''
emit('created', result.projectId)
} catch (cause) {
error.value = errorMessage(cause)
} finally {
busy.value = false
}
}
/** 创建项目表单校验规则。 */
const rules = {
title: requiredTextRule('项目标题'),
topic: requiredTextRule('故事主题'),
episodeCount: integerRule('计划集数')
}
</script>
<template>
<AppDialog
v-model:open="open"
title="新建剧本"
description="从一个故事想法开始。提交后,工作流将依次生成角色、世界观和剧集,并进行审核。"
:busy="busy"
>
<template #trigger
><NButton @click="open = true" type="primary"><Plus :size="16" />新建剧本</NButton></template
>
<AppForm
:model="form"
:rules="rules"
:disabled="busy"
:reset-key="open"
class="mt-7 space-y-4"
@submit="submit"
>
<!-- 以下是项目基本信息模块 -->
<NFormItem path="title" label="项目标题" :label-props="{ for: 'title' }"
><NInput
v-model:value="form.title"
placeholder="例如:记忆当铺"
:disabled="busy"
:input-props="{ id: 'title', autocomplete: 'off' }"
></NInput
></NFormItem>
<NFormItem path="topic" label="故事主题" :label-props="{ for: 'topic' }"
><NInput
placeholder="描述主角、故事背景,以及你希望展开的核心冲突……"
:disabled="busy"
:input-props="{ id: 'topic' }"
class="min-h-32 resize-y"
v-model:value="form.topic"
type="textarea"
:autosize="{ minRows: 3, maxRows: 12 }"
></NInput
></NFormItem>
<!-- 以下是生成参数模块 -->
<div class="grid grid-cols-1 gap-4">
<NFormItem path="style" label="剧本风格" :label-props="{ for: 'style' }"
><NInput
placeholder="如:都市悬疑、爽文反转"
:disabled="busy"
:input-props="{ id: 'style' }"
class="min-h-32 resize-y"
v-model:value="form.style"
type="textarea"
:autosize="{ minRows: 3, maxRows: 12 }"
></NInput
></NFormItem>
<NFormItem path="episodeCount" label="计划集数" :label-props="{ for: 'episode-count' }"
><NInputNumber
:disabled="busy"
:input-props="{ id: 'episode-count' }"
:value="typeof form.episodeCount === 'number' ? form.episodeCount : null"
@update:value="form.episodeCount = $event ?? 0"
:min="1"
:step="1"
></NInputNumber
></NFormItem>
</div>
<p class="text-xs leading-5 text-muted">
建议先用 1 集验证生成效果生成会实际调用后端模型产生相应费用
</p>
<NAlert v-if="error" role="alert" type="error" :show-icon="false" class=" ">{{ error }}</NAlert>
<div class="dialog-footer">
<NButton :disabled="busy" @click="open = false"> 取消</NButton
><NButton :disabled="busy" type="primary" attr-type="submit"
><LoaderCircle v-if="busy" :size="16" class="animate-spin" />开始生成<ArrowRight
v-if="!busy"
:size="16"
/></NButton>
</div>
</AppForm>
</AppDialog>
</template>