feat:z 优化
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1,306 +0,0 @@
|
|||||||
<template>
|
|
||||||
<a-modal
|
|
||||||
:open="visible"
|
|
||||||
title="我创建的"
|
|
||||||
:width="700"
|
|
||||||
:footer="null"
|
|
||||||
@cancel="handleClose"
|
|
||||||
>
|
|
||||||
<div class="favorites-content">
|
|
||||||
<!-- 操作栏 -->
|
|
||||||
<div class="action-bar">
|
|
||||||
<a-button type="primary" @click="handleCreate">
|
|
||||||
<template #icon><PlusOutlined /></template>
|
|
||||||
新建风格
|
|
||||||
</a-button>
|
|
||||||
<a-button @click="loadList" :loading="loading">
|
|
||||||
<template #icon><ReloadOutlined /></template>
|
|
||||||
刷新
|
|
||||||
</a-button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 列表 -->
|
|
||||||
<div class="favorites-list" v-if="!loading && list.length > 0">
|
|
||||||
<div
|
|
||||||
v-for="item in list"
|
|
||||||
:key="item.id"
|
|
||||||
class="favorite-card"
|
|
||||||
>
|
|
||||||
<div class="card-header">
|
|
||||||
<span class="card-name">{{ item.name }}</span>
|
|
||||||
<div class="card-actions">
|
|
||||||
<a-button type="link" size="small" @click="handleEdit(item)">编辑</a-button>
|
|
||||||
<a-popconfirm
|
|
||||||
title="确定删除此风格?"
|
|
||||||
@confirm="handleDelete(item.id)"
|
|
||||||
>
|
|
||||||
<a-button type="link" size="small" danger>删除</a-button>
|
|
||||||
</a-popconfirm>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card-content">{{ item.content }}</div>
|
|
||||||
<div class="card-footer">
|
|
||||||
<span class="card-category" v-if="item.category">{{ item.category }}</span>
|
|
||||||
<span class="card-use-count">使用 {{ item.useCount || 0 }} 次</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 空状态 -->
|
|
||||||
<div class="empty-state" v-if="!loading && list.length === 0">
|
|
||||||
<p>暂无收藏的风格</p>
|
|
||||||
<a-button type="primary" @click="handleCreate">立即创建</a-button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 加载状态 -->
|
|
||||||
<div class="loading-state" v-if="loading">
|
|
||||||
<a-spin />
|
|
||||||
<span>加载中...</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 编辑弹窗 -->
|
|
||||||
<a-modal
|
|
||||||
v-model:open="editVisible"
|
|
||||||
:title="editingItem ? '编辑风格' : '新建风格'"
|
|
||||||
:width="500"
|
|
||||||
@ok="handleSave"
|
|
||||||
:confirmLoading="saving"
|
|
||||||
>
|
|
||||||
<a-form layout="vertical">
|
|
||||||
<a-form-item label="风格名称" required>
|
|
||||||
<a-input v-model:value="editForm.name" placeholder="请输入风格名称" />
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item label="风格内容" required>
|
|
||||||
<a-textarea
|
|
||||||
v-model:value="editForm.content"
|
|
||||||
:rows="6"
|
|
||||||
placeholder="请输入风格提示词内容"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item label="分类">
|
|
||||||
<a-input v-model:value="editForm.category" placeholder="可选,用于分类管理" />
|
|
||||||
</a-form-item>
|
|
||||||
</a-form>
|
|
||||||
</a-modal>
|
|
||||||
</a-modal>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { ref, watch } from 'vue'
|
|
||||||
import { message } from 'ant-design-vue'
|
|
||||||
import { PlusOutlined, ReloadOutlined } from '@ant-design/icons-vue'
|
|
||||||
import { UserPromptApi } from '@/api/userPrompt'
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
visible: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const emit = defineEmits(['update:visible', 'refresh'])
|
|
||||||
|
|
||||||
const loading = ref(false)
|
|
||||||
const list = ref([])
|
|
||||||
const editVisible = ref(false)
|
|
||||||
const editingItem = ref(null)
|
|
||||||
const saving = ref(false)
|
|
||||||
|
|
||||||
const editForm = ref({
|
|
||||||
name: '',
|
|
||||||
content: '',
|
|
||||||
category: ''
|
|
||||||
})
|
|
||||||
|
|
||||||
// 加载列表
|
|
||||||
async function loadList() {
|
|
||||||
loading.value = true
|
|
||||||
try {
|
|
||||||
const res = await UserPromptApi.getUserPromptList()
|
|
||||||
if (res.code === 0) {
|
|
||||||
list.value = res.data || []
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('加载列表失败:', error)
|
|
||||||
} finally {
|
|
||||||
loading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建新风格
|
|
||||||
function handleCreate() {
|
|
||||||
editingItem.value = null
|
|
||||||
editForm.value = {
|
|
||||||
name: '',
|
|
||||||
content: '',
|
|
||||||
category: ''
|
|
||||||
}
|
|
||||||
editVisible.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 编辑风格
|
|
||||||
function handleEdit(item) {
|
|
||||||
editingItem.value = item
|
|
||||||
editForm.value = {
|
|
||||||
name: item.name,
|
|
||||||
content: item.content,
|
|
||||||
category: item.category || ''
|
|
||||||
}
|
|
||||||
editVisible.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 保存风格
|
|
||||||
async function handleSave() {
|
|
||||||
if (!editForm.value.name.trim()) {
|
|
||||||
message.warning('请输入风格名称')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (!editForm.value.content.trim()) {
|
|
||||||
message.warning('请输入风格内容')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
saving.value = true
|
|
||||||
try {
|
|
||||||
const data = {
|
|
||||||
name: editForm.value.name.trim(),
|
|
||||||
content: editForm.value.content.trim(),
|
|
||||||
category: editForm.value.category.trim() || null,
|
|
||||||
status: 1
|
|
||||||
}
|
|
||||||
|
|
||||||
if (editingItem.value) {
|
|
||||||
// 更新
|
|
||||||
await UserPromptApi.updateUserPrompt({
|
|
||||||
id: editingItem.value.id,
|
|
||||||
...data
|
|
||||||
})
|
|
||||||
message.success('更新成功')
|
|
||||||
} else {
|
|
||||||
// 创建
|
|
||||||
await UserPromptApi.createUserPrompt(data)
|
|
||||||
message.success('创建成功')
|
|
||||||
}
|
|
||||||
|
|
||||||
editVisible.value = false
|
|
||||||
loadList()
|
|
||||||
emit('refresh')
|
|
||||||
} catch (error) {
|
|
||||||
console.error('保存失败:', error)
|
|
||||||
message.error('保存失败')
|
|
||||||
} finally {
|
|
||||||
saving.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除风格
|
|
||||||
async function handleDelete(id) {
|
|
||||||
try {
|
|
||||||
await UserPromptApi.deleteUserPrompt(id)
|
|
||||||
message.success('删除成功')
|
|
||||||
loadList()
|
|
||||||
emit('refresh')
|
|
||||||
} catch (error) {
|
|
||||||
console.error('删除失败:', error)
|
|
||||||
message.error('删除失败')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 关闭弹窗
|
|
||||||
function handleClose() {
|
|
||||||
emit('update:visible', false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 监听 visible 变化
|
|
||||||
watch(() => props.visible, (newVal) => {
|
|
||||||
if (newVal) {
|
|
||||||
loadList()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped lang="less">
|
|
||||||
.favorites-content {
|
|
||||||
min-height: 300px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.action-bar {
|
|
||||||
display: flex;
|
|
||||||
gap: 12px;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.favorites-list {
|
|
||||||
display: grid;
|
|
||||||
gap: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.favorite-card {
|
|
||||||
padding: 16px;
|
|
||||||
border: 1px solid var(--color-border);
|
|
||||||
border-radius: 8px;
|
|
||||||
background: var(--color-surface);
|
|
||||||
transition: all 0.2s;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
border-color: var(--color-primary);
|
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-name {
|
|
||||||
font-weight: 600;
|
|
||||||
font-size: 15px;
|
|
||||||
color: var(--color-text);
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-actions {
|
|
||||||
display: flex;
|
|
||||||
gap: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-content {
|
|
||||||
color: var(--color-text-secondary);
|
|
||||||
font-size: 13px;
|
|
||||||
line-height: 1.6;
|
|
||||||
display: -webkit-box;
|
|
||||||
-webkit-line-clamp: 3;
|
|
||||||
-webkit-box-orient: vertical;
|
|
||||||
overflow: hidden;
|
|
||||||
margin-bottom: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-footer {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
font-size: 12px;
|
|
||||||
color: var(--color-text-tertiary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-category {
|
|
||||||
padding: 2px 8px;
|
|
||||||
background: rgba(24, 144, 255, 0.1);
|
|
||||||
color: #1890ff;
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.empty-state,
|
|
||||||
.loading-state {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
padding: 60px 20px;
|
|
||||||
color: var(--color-text-secondary);
|
|
||||||
gap: 16px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
<template>
|
|
||||||
<a-modal
|
|
||||||
v-model:open="modalVisible"
|
|
||||||
title="批量分组"
|
|
||||||
centered
|
|
||||||
@ok="handleConfirm"
|
|
||||||
@cancel="handleCancel"
|
|
||||||
>
|
|
||||||
<a-form layout="vertical">
|
|
||||||
<a-form-item label="选择分组" required>
|
|
||||||
<a-select
|
|
||||||
v-model:value="selectedGroupId"
|
|
||||||
placeholder="请选择要添加到的分组"
|
|
||||||
style="width: 100%"
|
|
||||||
>
|
|
||||||
<a-select-option v-for="group in groupList" :key="group.id" :value="group.id">
|
|
||||||
{{ group.name }}
|
|
||||||
</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
</a-form-item>
|
|
||||||
<div style="margin-top: 16px; padding: 12px; background: var(--color-bg-2); border-radius: var(--radius-card);">
|
|
||||||
<p style="margin: 0; font-size: 13px; color: var(--color-text-2);">
|
|
||||||
{{ groupingInfo }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</a-form>
|
|
||||||
</a-modal>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { ref, watch, computed } from 'vue'
|
|
||||||
import { message } from 'ant-design-vue'
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
open: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
groupList: {
|
|
||||||
type: Array,
|
|
||||||
default: () => []
|
|
||||||
},
|
|
||||||
// 可选的信息,组件会显示但不会强依赖
|
|
||||||
fileName: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
fileCount: {
|
|
||||||
type: Number,
|
|
||||||
default: 0
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const emit = defineEmits(['update:open', 'confirm', 'cancel'])
|
|
||||||
|
|
||||||
// 数据
|
|
||||||
const selectedGroupId = ref(null)
|
|
||||||
const modalVisible = ref(false)
|
|
||||||
|
|
||||||
// 计算分组提示信息
|
|
||||||
const groupingInfo = computed(() => {
|
|
||||||
if (props.fileName) {
|
|
||||||
return `将为文件 "${props.fileName}" 添加到选中的分组中`
|
|
||||||
}
|
|
||||||
if (props.fileCount > 0) {
|
|
||||||
return `将为 ${props.fileCount} 个文件添加到选中的分组中`
|
|
||||||
}
|
|
||||||
return '将为选中文件添加到选中的分组中'
|
|
||||||
})
|
|
||||||
|
|
||||||
// 监听 open 变化
|
|
||||||
watch(() => props.open, (newVal) => {
|
|
||||||
modalVisible.value = newVal
|
|
||||||
if (!newVal) {
|
|
||||||
selectedGroupId.value = null
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// 处理确认
|
|
||||||
const handleConfirm = () => {
|
|
||||||
if (!selectedGroupId.value) {
|
|
||||||
message.warning('请选择分组')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
emit('confirm', selectedGroupId.value)
|
|
||||||
handleCancel()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理取消
|
|
||||||
const handleCancel = () => {
|
|
||||||
modalVisible.value = false
|
|
||||||
selectedGroupId.value = null
|
|
||||||
emit('update:open', false)
|
|
||||||
emit('cancel')
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@@ -1,197 +0,0 @@
|
|||||||
<template>
|
|
||||||
<a-modal
|
|
||||||
v-model:open="modalVisible"
|
|
||||||
title="素材混剪"
|
|
||||||
centered
|
|
||||||
:confirm-loading="loading"
|
|
||||||
ok-text="确定"
|
|
||||||
cancel-text="取消"
|
|
||||||
@ok="handleConfirm"
|
|
||||||
@cancel="handleCancel"
|
|
||||||
>
|
|
||||||
<div class="mix-modal__summary">
|
|
||||||
<p>视频分组:{{ getGroupName(videoGroupId) || '未选择' }}</p>
|
|
||||||
<p>视频数量:{{ videoGroupFiles.length }} 个</p>
|
|
||||||
<p style="margin-top: 8px; font-size: 12px; color: var(--color-text-3);">
|
|
||||||
纯画面模式:仅拼接视频片段,无配音、无背景音乐
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<a-form layout="vertical">
|
|
||||||
<a-form-item label="选择视频分组" required>
|
|
||||||
<a-select
|
|
||||||
v-model:value="videoGroupId"
|
|
||||||
placeholder="请选择视频分组"
|
|
||||||
style="width: 100%"
|
|
||||||
@change="handleVideoGroupChange"
|
|
||||||
>
|
|
||||||
<a-select-option v-for="group in groupList" :key="group.id" :value="group.id">
|
|
||||||
{{ group.name }}
|
|
||||||
</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
</a-form-item>
|
|
||||||
|
|
||||||
<a-form-item label="视频标题" required>
|
|
||||||
<a-input v-model:value="mixForm.title" placeholder="请输入生成视频标题(仅用于记录)" />
|
|
||||||
<div style="margin-top: 8px; font-size: 12px; color: var(--color-text-3);">
|
|
||||||
标题仅用于任务记录,不会在视频上显示
|
|
||||||
</div>
|
|
||||||
</a-form-item>
|
|
||||||
</a-form>
|
|
||||||
</a-modal>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { ref, reactive, watch, computed } from 'vue'
|
|
||||||
import { message } from 'ant-design-vue'
|
|
||||||
import { MaterialService } from '@/api/material'
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
open: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
loading: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
groupList: {
|
|
||||||
type: Array,
|
|
||||||
default: () => []
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const emit = defineEmits(['update:open', 'confirm', 'cancel'])
|
|
||||||
|
|
||||||
// 数据
|
|
||||||
const modalVisible = ref(false)
|
|
||||||
const videoGroupId = ref(null)
|
|
||||||
const videoGroupFiles = ref([])
|
|
||||||
|
|
||||||
const mixForm = reactive({
|
|
||||||
title: ''
|
|
||||||
})
|
|
||||||
|
|
||||||
// 获取分组名称
|
|
||||||
const getGroupName = (groupId) => {
|
|
||||||
if (!groupId) return ''
|
|
||||||
const group = props.groupList.find(g => g.id === groupId)
|
|
||||||
return group?.name || ''
|
|
||||||
}
|
|
||||||
|
|
||||||
// 监听 open 变化
|
|
||||||
watch(() => props.open, (newVal) => {
|
|
||||||
modalVisible.value = newVal
|
|
||||||
if (newVal) {
|
|
||||||
resetForm()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// 处理视频分组变化
|
|
||||||
const handleVideoGroupChange = async (groupId) => {
|
|
||||||
console.log('[MaterialMixModal] handleVideoGroupChange called with groupId:', groupId)
|
|
||||||
|
|
||||||
if (!groupId) {
|
|
||||||
videoGroupFiles.value = []
|
|
||||||
console.log('[MaterialMixModal] groupId is empty, videoGroupFiles cleared')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('[MaterialMixModal] Loading video files for group:', groupId)
|
|
||||||
|
|
||||||
try {
|
|
||||||
const res = await MaterialService.getFilePage({
|
|
||||||
pageNo: 1,
|
|
||||||
pageSize: 100,
|
|
||||||
groupId: groupId,
|
|
||||||
fileCategory: 'video'
|
|
||||||
})
|
|
||||||
if (res.code === 0) {
|
|
||||||
videoGroupFiles.value = res.data.list || []
|
|
||||||
console.log('[MaterialMixModal] Loaded video files:', videoGroupFiles.value.length, 'files')
|
|
||||||
} else {
|
|
||||||
console.error('[MaterialMixModal] Failed to load video files:', res.msg)
|
|
||||||
message.error(res.msg || '加载分组文件失败')
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('[MaterialMixModal] Error loading video files:', error)
|
|
||||||
message.error('加载分组文件失败')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重置表单
|
|
||||||
const resetForm = () => {
|
|
||||||
mixForm.title = ''
|
|
||||||
videoGroupId.value = null
|
|
||||||
videoGroupFiles.value = []
|
|
||||||
}
|
|
||||||
|
|
||||||
// 暴露给父组件的方法
|
|
||||||
defineExpose({
|
|
||||||
resetForm
|
|
||||||
})
|
|
||||||
|
|
||||||
// 处理确认
|
|
||||||
const handleConfirm = async () => {
|
|
||||||
const title = mixForm.title.trim()
|
|
||||||
|
|
||||||
if (!videoGroupId.value) {
|
|
||||||
message.warning('请选择视频分组')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (!title) {
|
|
||||||
message.warning('请输入视频标题')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果当前没有视频文件,重新加载一次
|
|
||||||
if (videoGroupFiles.value.length === 0) {
|
|
||||||
message.loading('正在加载视频文件...', 0)
|
|
||||||
await handleVideoGroupChange(videoGroupId.value)
|
|
||||||
message.destroy()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (videoGroupFiles.value.length === 0) {
|
|
||||||
message.warning('所选分组下没有视频文件,请检查分组设置或更换分组')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 提取视频URL
|
|
||||||
const videoUrls = videoGroupFiles.value
|
|
||||||
.map(file => file?.fileUrl || file?.imgUrl)
|
|
||||||
.filter(Boolean)
|
|
||||||
|
|
||||||
if (videoUrls.length === 0) {
|
|
||||||
message.warning('视频分组中没有有效的视频文件')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
emit('confirm', {
|
|
||||||
title,
|
|
||||||
videoUrls
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理取消
|
|
||||||
const handleCancel = () => {
|
|
||||||
modalVisible.value = false
|
|
||||||
emit('update:open', false)
|
|
||||||
emit('cancel')
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.mix-modal__summary {
|
|
||||||
margin-bottom: 16px;
|
|
||||||
padding: 12px;
|
|
||||||
background: var(--color-bg-2);
|
|
||||||
border: 1px dashed var(--color-border);
|
|
||||||
border-radius: var(--radius-card);
|
|
||||||
font-size: 13px;
|
|
||||||
color: var(--color-text-2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.mix-modal__summary p {
|
|
||||||
margin: 0;
|
|
||||||
line-height: 1.6;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
Reference in New Issue
Block a user