Compare commits
5 Commits
7c3bd5c0e3
...
9b496bb42a
| Author | SHA1 | Date | |
|---|---|---|---|
| 9b496bb42a | |||
| 6afec090e4 | |||
| 7b53821cec | |||
| 9a215a89e9 | |||
| 1f5ad3abe2 |
@@ -63,10 +63,14 @@ const isSingle = computed(() => props.card.card_type === 'single_select')
|
|||||||
const isMulti = computed(() => props.card.card_type === 'multi_select' || props.card.card_type === 'mixed')
|
const isMulti = computed(() => props.card.card_type === 'multi_select' || props.card.card_type === 'mixed')
|
||||||
|
|
||||||
const canSubmit = computed(() => {
|
const canSubmit = computed(() => {
|
||||||
|
// 纯文本输入卡片:只需 customText 非空
|
||||||
|
if (isTextInput.value) return customText.value.trim().length > 0
|
||||||
|
|
||||||
|
// 有选项的卡片:满足最小选择数,或(允许自定义且 customText 非空)
|
||||||
const minSel = props.card.min_selections || 1
|
const minSel = props.card.min_selections || 1
|
||||||
if (selectedValues.value.length < minSel) return false
|
if (selectedValues.value.length >= minSel) return true
|
||||||
if (isTextInput.value && !customText.value.trim()) return false
|
if (props.card.allow_custom && customText.value.trim()) return true
|
||||||
return true
|
return false
|
||||||
})
|
})
|
||||||
|
|
||||||
function isSelected(value) {
|
function isSelected(value) {
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ import { useAppStore } from '../../stores/app.js'
|
|||||||
import { toggleFavoriteScript, checkFavoriteScript } from '../../services/epicScript.js'
|
import { toggleFavoriteScript, checkFavoriteScript } from '../../services/epicScript.js'
|
||||||
|
|
||||||
const store = useAppStore()
|
const store = useAppStore()
|
||||||
const activeType = ref('long')
|
const activeType = ref('all')
|
||||||
const activeStatus = ref('all')
|
const activeStatus = ref('all')
|
||||||
const keyword = ref('')
|
const keyword = ref('')
|
||||||
const sortMode = ref('updated')
|
const sortMode = ref('updated')
|
||||||
@@ -162,11 +162,18 @@ const activeMenuId = ref('')
|
|||||||
const deleteTarget = ref(null)
|
const deleteTarget = ref(null)
|
||||||
const deletingScript = ref(false)
|
const deletingScript = ref(false)
|
||||||
|
|
||||||
const typeTabs = [
|
// length 字段值 → 显示标签映射
|
||||||
{ label: '长篇', value: 'long' },
|
const LENGTH_LABELS = { short: '短篇', medium: '中篇', long: '长篇' }
|
||||||
{ label: '短篇', value: 'short' },
|
|
||||||
{ label: '风格', value: 'style' }
|
// 从实际剧本数据中提取分类标签,禁止硬编码
|
||||||
]
|
const typeTabs = computed(() => {
|
||||||
|
const lengths = new Set(scripts.value.map(s => s.length || 'medium'))
|
||||||
|
const tabs = [{ label: '全部', value: 'all' }]
|
||||||
|
lengths.forEach(l => {
|
||||||
|
tabs.push({ label: LENGTH_LABELS[l] || l, value: l })
|
||||||
|
})
|
||||||
|
return tabs
|
||||||
|
})
|
||||||
|
|
||||||
const statusFilters = [
|
const statusFilters = [
|
||||||
{ label: '全部', value: 'all' },
|
{ label: '全部', value: 'all' },
|
||||||
@@ -187,8 +194,8 @@ const visibleScripts = computed(() => {
|
|||||||
}
|
}
|
||||||
if (activeStatus.value === 'favorite') return isFavorite(script)
|
if (activeStatus.value === 'favorite') return isFavorite(script)
|
||||||
if (activeStatus.value !== 'all' && status !== activeStatus.value) return false
|
if (activeStatus.value !== 'all' && status !== activeStatus.value) return false
|
||||||
if (activeType.value === 'short') return script.length === 'short'
|
// 精确匹配 length 字段,禁止硬编码分类
|
||||||
if (activeType.value === 'long') return script.length !== 'short'
|
if (activeType.value !== 'all') return script.length === activeType.value
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
return [...filtered].sort((a, b) => {
|
return [...filtered].sort((a, b) => {
|
||||||
|
|||||||
@@ -157,7 +157,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view v-if="!msg.confirmed" class="outline-actions">
|
<view v-if="!msg.confirmed" class="outline-actions">
|
||||||
<input v-model="msg.feedback" placeholder="如需修改请输入意见" class="outline-feedback" />
|
<textarea v-model="msg.feedback" placeholder="如需修改请输入意见" class="outline-feedback" auto-height />
|
||||||
<view class="outline-buttons">
|
<view class="outline-buttons">
|
||||||
<view class="btn-secondary" @click="modifyOutline(msg)">修改大纲</view>
|
<view class="btn-secondary" @click="modifyOutline(msg)">修改大纲</view>
|
||||||
<view class="btn-primary" @click="confirmOutline(msg)">确认大纲</view>
|
<view class="btn-primary" @click="confirmOutline(msg)">确认大纲</view>
|
||||||
@@ -1711,7 +1711,7 @@ const handleShortNovelEvent = (event) => {
|
|||||||
pendingNextResponse.value = false
|
pendingNextResponse.value = false
|
||||||
break
|
break
|
||||||
case 'novel_delta': {
|
case 'novel_delta': {
|
||||||
// 往最后一条 novel 消息追加 delta
|
// 往最后一条 pending novel 消息直接累加 delta,保证流式显示
|
||||||
const lastNovel = [...resultMessages.value].reverse().find(m => m.kind === 'novel' && m.pending)
|
const lastNovel = [...resultMessages.value].reverse().find(m => m.kind === 'novel' && m.pending)
|
||||||
if (lastNovel) {
|
if (lastNovel) {
|
||||||
lastNovel.content += payload.delta || ''
|
lastNovel.content += payload.delta || ''
|
||||||
@@ -1733,6 +1733,8 @@ const handleShortNovelEvent = (event) => {
|
|||||||
generationStatus.value = 'idle'
|
generationStatus.value = 'idle'
|
||||||
pendingNextResponse.value = false
|
pendingNextResponse.value = false
|
||||||
persistResultMessages()
|
persistResultMessages()
|
||||||
|
// 从后端刷新剧本列表,确保新生成的短篇出现在历史中(非阻塞)
|
||||||
|
store.fetchScripts()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'error':
|
case 'error':
|
||||||
@@ -1773,6 +1775,7 @@ const submitClarification = (answer) => {
|
|||||||
|
|
||||||
const confirmOutline = (msg) => {
|
const confirmOutline = (msg) => {
|
||||||
if (msg) msg.confirmed = true
|
if (msg) msg.confirmed = true
|
||||||
|
pendingNextResponse.value = true
|
||||||
addResultMessage({ role: 'user', kind: 'text', content: '确认大纲' })
|
addResultMessage({ role: 'user', kind: 'text', content: '确认大纲' })
|
||||||
currentStreamTask.value = followupStream({
|
currentStreamTask.value = followupStream({
|
||||||
sessionId: novelSessionId.value,
|
sessionId: novelSessionId.value,
|
||||||
@@ -1790,6 +1793,7 @@ const modifyOutline = (msg) => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (msg) msg.confirmed = true
|
if (msg) msg.confirmed = true
|
||||||
|
pendingNextResponse.value = true
|
||||||
addResultMessage({ role: 'user', kind: 'text', content: feedback })
|
addResultMessage({ role: 'user', kind: 'text', content: feedback })
|
||||||
currentStreamTask.value = followupStream({
|
currentStreamTask.value = followupStream({
|
||||||
sessionId: novelSessionId.value,
|
sessionId: novelSessionId.value,
|
||||||
@@ -2285,11 +2289,14 @@ onUnmounted(() => {
|
|||||||
|
|
||||||
.outline-feedback {
|
.outline-feedback {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 20rpx;
|
min-height: 64rpx;
|
||||||
|
max-height: 120rpx;
|
||||||
|
padding: 16rpx 20rpx;
|
||||||
background: rgba(255, 255, 255, 0.05);
|
background: rgba(255, 255, 255, 0.05);
|
||||||
border-radius: 12rpx;
|
border-radius: 12rpx;
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
|
line-height: 1.5;
|
||||||
margin-bottom: 24rpx;
|
margin-bottom: 24rpx;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
@@ -3738,11 +3745,14 @@ onUnmounted(() => {
|
|||||||
|
|
||||||
.outline-feedback {
|
.outline-feedback {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 20rpx;
|
min-height: 64rpx;
|
||||||
|
max-height: 120rpx;
|
||||||
|
padding: 16rpx 20rpx;
|
||||||
background: rgba(255, 255, 255, 0.05);
|
background: rgba(255, 255, 255, 0.05);
|
||||||
border-radius: 12rpx;
|
border-radius: 12rpx;
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
|
line-height: 1.5;
|
||||||
margin-bottom: 16rpx;
|
margin-bottom: 16rpx;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user