优化
This commit is contained in:
@@ -66,20 +66,21 @@
|
||||
:title="groupModalTitle"
|
||||
@ok="handleSaveGroup"
|
||||
@cancel="handleCancelGroup"
|
||||
@close="handleCancelGroup"
|
||||
>
|
||||
<a-form :model="groupForm" :label-col-props="{ span: 6 }" :wrapper-col-props="{ span: 18 }">
|
||||
<a-form-item label="分组名称" field="name" :rules="[{ required: true, message: '请输入分组名称' }]">
|
||||
<a-input v-model="groupForm.name" placeholder="请输入分组名称" />
|
||||
<a-form ref="groupFormRef" :model="groupForm" layout="vertical">
|
||||
<a-form-item label="分组名称" name="name" :rules="[{ required: true, message: '请输入分组名称' }]">
|
||||
<a-input v-model:value="groupForm.name" placeholder="请输入分组名称" />
|
||||
</a-form-item>
|
||||
<a-form-item label="分组描述" field="description">
|
||||
<a-form-item label="分组描述" name="description">
|
||||
<a-textarea
|
||||
v-model="groupForm.description"
|
||||
v-model:value="groupForm.description"
|
||||
placeholder="请输入分组描述"
|
||||
:auto-size="{ minRows: 3, maxRows: 5 }"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="排序" field="sort">
|
||||
<a-input-number v-model="groupForm.sort" :min="0" placeholder="排序值" />
|
||||
<a-form-item label="排序" name="sort">
|
||||
<a-input-number v-model:value="groupForm.sort" :min="0" placeholder="排序值" />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
@@ -102,6 +103,7 @@ const groupList = ref([])
|
||||
const groupModalVisible = ref(false)
|
||||
const groupModalTitle = ref('新建分组')
|
||||
const isEdit = ref(false)
|
||||
const groupFormRef = ref(null)
|
||||
|
||||
// 表单
|
||||
const groupForm = reactive({
|
||||
@@ -141,6 +143,10 @@ const handleCreateGroup = () => {
|
||||
groupForm.description = ''
|
||||
groupForm.sort = 0
|
||||
groupModalVisible.value = true
|
||||
// 清除表单验证状态
|
||||
setTimeout(() => {
|
||||
groupFormRef.value?.clearValidate()
|
||||
}, 0)
|
||||
}
|
||||
|
||||
// 编辑分组
|
||||
@@ -152,16 +158,18 @@ const handleEditGroup = (group) => {
|
||||
groupForm.description = group.description || ''
|
||||
groupForm.sort = group.sort || 0
|
||||
groupModalVisible.value = true
|
||||
// 清除表单验证状态
|
||||
setTimeout(() => {
|
||||
groupFormRef.value?.clearValidate()
|
||||
}, 0)
|
||||
}
|
||||
|
||||
// 保存分组
|
||||
const handleSaveGroup = async () => {
|
||||
if (!groupForm.name.trim()) {
|
||||
message.warning('请输入分组名称')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
// 验证表单
|
||||
const values = await groupFormRef.value.validateFields()
|
||||
|
||||
if (isEdit.value) {
|
||||
await MaterialGroupService.updateGroup(groupForm)
|
||||
message.success('更新成功')
|
||||
@@ -172,6 +180,10 @@ const handleSaveGroup = async () => {
|
||||
groupModalVisible.value = false
|
||||
loadGroupList()
|
||||
} catch (error) {
|
||||
if (error?.errorFields) {
|
||||
// 表单验证失败,不显示错误提示(Ant Design会自动显示)
|
||||
return
|
||||
}
|
||||
console.error('保存分组失败:', error)
|
||||
message.error(error.message || '保存失败,请重试')
|
||||
}
|
||||
@@ -184,6 +196,8 @@ const handleCancelGroup = () => {
|
||||
groupForm.name = ''
|
||||
groupForm.description = ''
|
||||
groupForm.sort = 0
|
||||
// 清除表单验证状态
|
||||
groupFormRef.value?.resetFields()
|
||||
}
|
||||
|
||||
// 删除分组
|
||||
|
||||
@@ -9,10 +9,17 @@
|
||||
</template>
|
||||
上传素材
|
||||
</a-button>
|
||||
<a-button
|
||||
v-if="selectedFileIds.length > 0"
|
||||
type="primary"
|
||||
ghost
|
||||
@click="handleOpenGroupModal"
|
||||
>
|
||||
批量分组 ({{ selectedFileIds.length }})
|
||||
</a-button>
|
||||
<a-button
|
||||
type="primary"
|
||||
ghost
|
||||
:disabled="selectedFileIds.length === 0"
|
||||
@click="handleOpenMixModal"
|
||||
>
|
||||
素材混剪
|
||||
@@ -120,6 +127,10 @@
|
||||
<div class="material-item__delete" @click.stop="handleDeleteFile(file)">
|
||||
<DeleteOutlined />
|
||||
</div>
|
||||
<!-- 分组图标 -->
|
||||
<div class="material-item__group" @click.stop="handleSingleGroup(file)">
|
||||
<TagsOutlined />
|
||||
</div>
|
||||
</div>
|
||||
<!-- 文件信息 -->
|
||||
<div class="material-item__info">
|
||||
@@ -160,6 +171,35 @@
|
||||
@confirm="handleConfirmUpload"
|
||||
@cancel="handleUploadCancel"
|
||||
/>
|
||||
|
||||
<!-- 批量分组模态框 -->
|
||||
<a-modal
|
||||
v-model:open="groupModalVisible"
|
||||
title="批量分组"
|
||||
centered
|
||||
@ok="handleBatchGroup"
|
||||
@cancel="handleGroupCancel"
|
||||
>
|
||||
<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>
|
||||
|
||||
<a-modal
|
||||
v-model:open="mixModalVisible"
|
||||
title="素材混剪"
|
||||
@@ -171,9 +211,11 @@
|
||||
@cancel="handleMixCancel"
|
||||
>
|
||||
<div class="mix-modal__summary">
|
||||
<p>选中素材:{{ selectedFiles.length }} 个</p>
|
||||
<p>视频素材:{{ selectedVideoUrls.length }} 个</p>
|
||||
<p>背景音乐:{{ selectedAudioUrls.length }} 个</p>
|
||||
<p>视频素材:{{ allVideoUrls.length }} 个</p>
|
||||
<p>背景音乐:{{ allAudioUrls.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>
|
||||
@@ -206,9 +248,10 @@ import {
|
||||
UploadOutlined,
|
||||
SearchOutlined,
|
||||
FileOutlined,
|
||||
DeleteOutlined
|
||||
DeleteOutlined,
|
||||
TagsOutlined
|
||||
} from '@ant-design/icons-vue'
|
||||
import { MaterialService } from '@/api/material'
|
||||
import { MaterialService, MaterialGroupService } from '@/api/material'
|
||||
import { MixService } from '@/api/mix'
|
||||
import MaterialUploadModal from '@/components/material/MaterialUploadModal.vue'
|
||||
import { formatFileSize, formatDate } from '@/utils/file'
|
||||
@@ -222,6 +265,12 @@ const uploading = ref(false)
|
||||
const mixModalVisible = ref(false)
|
||||
const mixing = ref(false)
|
||||
|
||||
// 分组相关
|
||||
const groupModalVisible = ref(false)
|
||||
const groupList = ref([])
|
||||
const selectedGroupId = ref(null)
|
||||
const groupingFileId = ref(null) // 当前正在分组的单个文件ID
|
||||
|
||||
// 筛选条件
|
||||
const filters = reactive({
|
||||
fileCategory: 'video', // 默认分类为视频
|
||||
@@ -485,6 +534,28 @@ const selectedAudioUrls = computed(() =>
|
||||
selectedFiles.value.map((file) => (isAudioFile(file) ? file?.fileUrl || file?.previewUrl : null)).filter(Boolean)
|
||||
)
|
||||
|
||||
// 获取所有视频素材
|
||||
const allVideoUrls = computed(() =>
|
||||
fileList.value.map((file) => (isVideoFile(file) ? file?.fileUrl || file?.previewUrl : null)).filter(Boolean)
|
||||
)
|
||||
|
||||
// 获取所有音频素材
|
||||
const allAudioUrls = computed(() =>
|
||||
fileList.value.map((file) => (isAudioFile(file) ? file?.fileUrl || file?.previewUrl : null)).filter(Boolean)
|
||||
)
|
||||
|
||||
// 分组提示信息
|
||||
const groupingInfo = computed(() => {
|
||||
if (groupingFileId.value) {
|
||||
// 单个文件分组
|
||||
const file = fileList.value.find(f => f.id === groupingFileId.value)
|
||||
return file ? `将为文件 "${file.fileName}" 添加到选中的分组中` : ''
|
||||
} else {
|
||||
// 批量分组
|
||||
return `将为 ${selectedFileIds.value.length} 个文件添加到选中的分组中`
|
||||
}
|
||||
})
|
||||
|
||||
const mixForm = reactive({
|
||||
title: '',
|
||||
text: '',
|
||||
@@ -498,16 +569,13 @@ const resetMixForm = () => {
|
||||
}
|
||||
|
||||
const handleOpenMixModal = () => {
|
||||
if (selectedFileIds.value.length === 0) {
|
||||
message.warning('请先选择至少一个素材')
|
||||
// 检查是否有可用的视频和音频素材
|
||||
if (allVideoUrls.value.length === 0) {
|
||||
message.warning('暂无可用的视频素材')
|
||||
return
|
||||
}
|
||||
if (selectedVideoUrls.value.length === 0) {
|
||||
message.warning('请至少选择一个视频素材')
|
||||
return
|
||||
}
|
||||
if (selectedAudioUrls.value.length === 0) {
|
||||
message.warning('请至少选择一个背景音乐素材')
|
||||
if (allAudioUrls.value.length === 0) {
|
||||
message.warning('暂无可用的音频素材')
|
||||
return
|
||||
}
|
||||
mixModalVisible.value = true
|
||||
@@ -529,21 +597,24 @@ const handleMixConfirm = async () => {
|
||||
return
|
||||
}
|
||||
const produceCount = Math.max(1, Math.min(10, Number(mixForm.produceCount) || 1))
|
||||
if (selectedVideoUrls.value.length === 0) {
|
||||
message.warning('请至少选择一个视频素材')
|
||||
|
||||
// 再次检查素材可用性
|
||||
if (allVideoUrls.value.length === 0) {
|
||||
message.warning('暂无可用的视频素材')
|
||||
return
|
||||
}
|
||||
if (selectedAudioUrls.value.length === 0) {
|
||||
message.warning('请至少选择一个背景音乐素材')
|
||||
if (allAudioUrls.value.length === 0) {
|
||||
message.warning('暂无可用的音频素材')
|
||||
return
|
||||
}
|
||||
|
||||
mixing.value = true
|
||||
try {
|
||||
const { data } = await MixService.batchProduceAlignment({
|
||||
title,
|
||||
text,
|
||||
videoUrls: selectedVideoUrls.value,
|
||||
bgMusicUrls: selectedAudioUrls.value,
|
||||
videoUrls: allVideoUrls.value,
|
||||
bgMusicUrls: allAudioUrls.value,
|
||||
produceCount
|
||||
})
|
||||
const jobIds = Array.isArray(data) ? data : []
|
||||
@@ -565,7 +636,87 @@ const handleMixConfirm = async () => {
|
||||
// 初始化
|
||||
onMounted(() => {
|
||||
loadFileList()
|
||||
loadGroupList()
|
||||
})
|
||||
|
||||
// 加载分组列表
|
||||
const loadGroupList = async () => {
|
||||
try {
|
||||
const res = await MaterialGroupService.getGroupList()
|
||||
if (res.code === 0) {
|
||||
groupList.value = res.data || []
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载分组列表失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 打开批量分组模态框
|
||||
const handleOpenGroupModal = () => {
|
||||
if (selectedFileIds.value.length === 0) {
|
||||
message.warning('请先选择要分组的文件')
|
||||
return
|
||||
}
|
||||
groupingFileId.value = null // 清空单个文件分组标记
|
||||
groupModalVisible.value = true
|
||||
}
|
||||
|
||||
// 单个文件分组
|
||||
const handleSingleGroup = (file) => {
|
||||
groupingFileId.value = file.id // 标记是单个文件分组
|
||||
groupModalVisible.value = true
|
||||
}
|
||||
|
||||
// 执行批量分组
|
||||
const handleBatchGroup = async () => {
|
||||
if (!selectedGroupId.value) {
|
||||
message.warning('请选择分组')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
let fileIds
|
||||
let successMessage
|
||||
|
||||
if (groupingFileId.value) {
|
||||
// 单个文件分组
|
||||
fileIds = [groupingFileId.value]
|
||||
successMessage = '文件分组成功'
|
||||
} else {
|
||||
// 批量分组
|
||||
fileIds = selectedFileIds.value
|
||||
successMessage = '批量分组成功'
|
||||
}
|
||||
|
||||
await MaterialGroupService.addFilesToGroups({
|
||||
fileIds: fileIds,
|
||||
groupIds: [selectedGroupId.value]
|
||||
})
|
||||
message.success(successMessage)
|
||||
|
||||
// 重置状态
|
||||
groupModalVisible.value = false
|
||||
selectedGroupId.value = null
|
||||
groupingFileId.value = null
|
||||
|
||||
// 如果是批量分组,清除选中状态
|
||||
if (!groupingFileId.value) {
|
||||
selectedFileIds.value = []
|
||||
}
|
||||
|
||||
loadGroupList() // 刷新分组列表以更新文件计数
|
||||
} catch (error) {
|
||||
console.error('分组失败:', error)
|
||||
message.error(error.message || '分组失败,请重试')
|
||||
}
|
||||
}
|
||||
|
||||
// 取消分组操作
|
||||
const handleGroupCancel = () => {
|
||||
groupModalVisible.value = false
|
||||
selectedGroupId.value = null
|
||||
groupingFileId.value = null
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@@ -699,15 +850,42 @@ onMounted(() => {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.material-item__group {
|
||||
position: absolute;
|
||||
bottom: 8px;
|
||||
right: 42px; /* 在删除按钮左边 */
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
background: rgba(24, 144, 255, 0.9);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
transition: all 0.3s;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.material-item:hover .material-item__delete {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.material-item:hover .material-item__group {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.material-item__delete:hover {
|
||||
background: rgb(255, 77, 79);
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.material-item__group:hover {
|
||||
background: rgb(24, 144, 255);
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.material-item__info {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user